An analysis of the NSO BLASTPASS iMessage exploit
Posted by Ian Beer, Google Project Zero
On September 7, 2023 Apple issued an out-of-band security update for iOS:
Around the same time on September 7th 2023, Citizen Lab published a blog post linking the two CVEs fixed in iOS 16.6.1 to an “NSO Group Zero-Click, Zero-Day exploit captured in the wild”:
“[The target was] an individual employed by a Washington DC-based civil society organization with international offices…
The exploit chain was capable of compromising iPhones running the latest version of iOS (16.6) without any interaction from the victim.
The exploit involved PassKit attachments containing malicious images sent from an attacker iMessage account to the victim.”
The day before, on September 6th 2023, Apple reported a vulnerability to the WebP project, indicating in the report that they planned to ship a custom fix for Apple customers the next day.
The WebP team posted their first proposed fix in the public git repo the next day, and five days after that on September 12th Google released a new Chrome stable release containing the WebP fix. Both Apple and Google marked the issue as exploited in the wild, alerting other integrators of WebP that they should rapidly integrate the fix as well as causing the security research community to take a closer look…
A couple of weeks later on September 21st 2023, former Project Zero team lead Ben Hawkes (in collaboration with @mistymntncop) published the first detailed writeup of the root cause of the vulnerability on the Isosceles Blog. A couple of months later, on November 3rd, a group called Dark Navy published their first blog post: a two-part analysis (Part 1 – Part 2) of the WebP vulnerability and a proof-of-concept exploit targeting Chrome (CVE-2023-4863).
Whilst the Isosceles and Dark Navy posts explained the underlying memory corruption vulnerability in great detail, they were unable to solve another fascinating part of the puzzle: just how exactly do you land an exploit for this vulnerability in a one-shot, zero-click setup? As we’ll soon see, the corruption primitive is very limited. Without access to the samples it was almost impossible to know.
In mid-November, in collaboration with Amnesty International Security Lab, I was able to obtain a number of BLASTPASS PKPass sample files as well as crash logs from failed exploit attempts.
This blog post covers my analysis of those samples and the journey to figure out how one of NSO’s recent zero-click iOS exploits really worked. For me that journey began by immediately taking three months of paternity leave, and resumed in March 2024 where this story begins:
Setting the scene
For a detailed analysis of the root-cause of the WebP vulnerability and the primitive it yields, I recommend first reading the three blog posts I mentioned earlier (Isosceles, Dark Navy 1, Dark Navy 2.) I won’t restate their analyses here (both because you should read their original work, and because it’s quite complicated!) Instead I’ll briefly discuss WebP and the corruption primitive the vulnerability yields.
WebP
WebP is a relatively modern image file format, first released in 2010. In reality WebP is actually two completely distinct image formats: a lossy format based on the VP8 video codec and a separate lossless format. The two formats share nothing apart from both using a RIFF container and the string WEBP for the first chunk name. From that point on (12 bytes into the file) they are completely different. The vulnerability is in the lossless format, with the RIFF chunk name VP8L.
Lossless WebP makes extensive use of Huffman coding; there are at least 10 huffman trees present in the BLASTPASS sample. In the file they’re stored as canonical huffman trees, meaning that only the code lengths are retained. At decompression time those lengths are converted directly into a two-level huffman decoding table, with the five largest tables all getting squeezed together into the same pre-allocated buffer. The (it turns out not quite) maximum size of these tables is pre-computed based on the number of symbols they encode. If you’re up to this part and you’re slightly lost, the other three blogposts referenced above explain this in detail.
With control over the symbol lengths it’s possible to define all sorts of strange trees, many of which aren’t valid. The fundamental issue was that the WebP code only checked the validity of the tree after building the decoding table. But the pre-computed size of the decoding table was only correct for valid trees.
As the Isosceles blog post points out, this means that a fundamental part of the vulnerability is that triggering the bug is detected, though after memory has been corrupted, and image parsing stops only a few lines of code later. This presents another exploitation mystery: in a zero-click context, how do you exploit a bug where every time the issue is triggered it also stops parsing any attacker-controlled data?
The second mystery involves the actual corruption primitive. The vulnerability will write a HuffmanCode structure at a known offset past the end of the huffman tables buffer:
// Huffman lookup table entry
typedef struct {
uint8_t bits;
uint16_t value;
} HuffmanCode;
As DarkNavy point out, whilst the bits and value fields are nominally attacker-controlled, in reality there isn’t that much flexibility. The fifth huffman table (the one at the end of the preallocated buffer, part of which can get written out-of-bounds) only has 40 symbols, limiting value to a maximum value of 39 (0x27) and bits will be between 1 and 7 (for a second-level table entry). There’s a padding byte between bits and value which makes the largest value that could be written out-of-bounds 0x00270007. And it just so happens that that’s exactly the value which the exploit does write — and they likely didn’t have that much choice about it.
There’s also not much flexibility in the huffman table allocation size. The table allocation in the exploit is 12072 (0x2F28) bytes, which will get rounded up to fit within a 0x3000 byte libmalloc small region. The code lengths are chosen such that the overflow occurs like this:
To summarize: The 32-bit value 0x270007 will be written 0x58 bytes past the end of a 0x3000 byte huffman table allocation. And then WebP parsing will fail, and the decoder will bail out.
Déjà vu?
Long-term readers of the Project Zero blog might be experiencing a sense of déjà vu at this point… haven’t I already written a blog post about an NSO zero-click iPhone zero day exploiting a vulnerability in a slightly obscure lossless compression format used in an image parsed from an iMessage attachment?
BLASTPASS has many similarities with FORCEDENTRY, and my initial hunch (which turned out to be completely wrong) was that this exploit might take a similar approach to build a weird machine using some fancier WebP features. To that end I started out by writing a WebP parser to see what features were actually used.
Transformation
In a very similar fashion to JBIG2, WebP also supports invertible transformations on the input pixel data:
My initial theory was that the exploit might operate in a similar fashion to FORCEDENTRY and apply sequences of these transformations outside of the bounds of the image buffer to build a weird machine. But after implementing enough of the WebP format in python to parse every bit of the VP8L chunk it became pretty clear that it was only triggering the Huffman table overflow and nothing more. The VP8L chunk was only 1052 bytes, and pretty much all of it was the 10 Huffman tables needed to trigger the overflow.
What’s in a pass?
Although BLASTPASS is often referred to as an exploit for “the WebP vulnerability”, the attackers don’t actually just send a WebP file (even though that is supported in iMessage). They send a PassKit PKPass file, which contains a WebP. There must be a reason for this. So let’s step back and actually take a look at one of the sample files I received:
171K sample.pkpass
$ file sample.pkpass
sample.pkpass: Zip archive data, at least v2.0 to extract, compression method=deflate
There are five files inside the PKPass zip archive:
60K background.png
5.5M logo.png
175B manifest.json
18B pass.json
3.3K signature
The 5.5MB logo.png is the WebP image, just with a .png extension instead of .webp:
$ file logo.png:
logo.png: RIFF (little-endian) data, Web/P image
The closest thing to a specification for the PKPass format appears to be the Wallet Developer Guide, and whilst it doesn’t explicitly state that the .png files should actually be Portable Network Graphics images, that’s presumably the intention. This is yet another parallel with FORCEDENTRY, where a similar trick was used to reach the PDF parser when attempting to parse a GIF.
PKPass files require a valid signature which is contained in manifest.json and signature. The signature has a presumably fake name and more timestamps indicating that the PKPass is very likely being generated and signed on the fly for each exploit attempt.
pass.json is just this:
{“pass”: “PKpass”}
Finally background.png:
$ file background.png
background.png: TIFF image data, big-endian, direntries=15, height=16, bps=0, compression=deflate, PhotometricIntepretation=RGB, orientation=upper-left, width=48
Curious. Another file with a misleading extension; this time a TIFF file with a .png extension.
We’ll return to this TIFF later in the analysis as it plays a critical role in the exploit flow, but for now we’ll focus on the WebP, with one short diversion:
Blastdoor
So far I’ve only mentioned the WebP vulnerability, but the Apple advisory I linked at the start of this post mentions two separate CVEs:
The first, CVE-2023-41064 in ImageIO, is the WebP bug (though just to keep things confusing with a different CVE from the upstream WebP fix which is CVE-2023-4863 – they’re the same vulnerability though).
The second, CVE-2023-41061 in “Wallet”, is described in the Apple advisory as: “A maliciously crafted attachment may result in arbitrary code execution“.
The Isosceles blog post hypothesises:
“Citizen Lab called this attack “BLASTPASS”, since the attackers found a clever way to bypass the “BlastDoor” iMessage sandbox. We don’t have the full technical details, but it looks like by bundling an image exploit in a PassKit attachment, the malicious image would be processed in a different, unsandboxed process. This corresponds to the first CVE that Apple released, CVE-2023-41061.“
This theory makes sense — FORCEDENTRY had a similar trick where the JBIG2 bug was actually exploited inside IMTranscoderAgent instead of the more restrictive sandbox of BlastDoor. But in all my experimentation, as well as all the in-the-wild crash logs I’ve seen, this hypothesis doesn’t seem to hold.
The PKPass file and the images enclosed within do get parsed inside the BlastDoor sandbox and that’s where the crashes occur or the payload executes — later on we’ll also see evidence that the NSExpression payload which eventually gets evaluated expects to be running inside BlastDoor.
My guess is that CVE-2023-41061 is more likely referring to the lax parsing of PKPasses which didn’t reject images which weren’t png’s.
In late 2024, I received another set of in-the-wild crash logs including two which do in fact strongly indicate that there was also a path to hit the WebP vulnerability in the MobileSMS process, outside the BlastDoor sandbox! Interestingly, the timestamps indicate that these devices were targeted in November 2023, two months after the vulnerability was patched.
In those cases the WebP code was reached inside the MobileSMS process via a ChatKit CKPassPreviewMediaObject created by a CKAttachmentMessagePartChatItem.
What’s in a WebP?
I mentioned that the VP8L chunk in the WebP file is only around 1KB. Yet in the file listing above the WebP file is 5.5MB! So what’s in the rest of it? Expanding out my WebP parser we see that there’s one more RIFF chunk:
EXIF : 0x586bb8
exif is Intel byte alignment
EXIF has n_entries=1
tag=8769 fmt=4 n_components=1 data=1a
subIFD has n_entries=1
tag=927c fmt=7 n_components=586b8c data=2c
It’s a (really really huge) EXIF – the standard format which cameras use to store image metadata — stuff like the camera model, exposure time, f-stop etc.
It’s a tag-based format and pretty much all 5.5MB is inside one tag with the id 0x927c. So what’s that?
Looking through an online list of EXIF tags just below the lens FocalLength tag and above the UserComment tag we spot 0x927c:
It’s the very-vague-yet-fascinating sounding: “MakerNote – Manufacturer specific information.“
Looking to Wikipedia for some clarification on what that actually is, we learn that
“the “MakerNote” tag contains information normally in a proprietary binary format.”
Modifying the webp parser to now dump out the MakerNote tag we see:
$ file sample.makernote
sample.makernote: Apple binary property list
Apple’s chosen format for the “proprietary binary format” is binary plist!
And indeed: looking through the ImageIO library in IDA there’s a clear path between the WebP parser, the EXIF parser, the MakerNote parser and the binary plist parser.
unbplisting
I covered the binary plist format in a previous blog post. That was the second time I’d had to analyse a large bplist. The first time (for the FORCEDENTRY sandbox escape) it was possible mostly by hand, just using the human-readable output of plutil. Last year, for the Safari sandbox escape analysis, the bplist was 437KB and I had to write a custom bplist parser to figure out what was going on. Keeping the exponential curve going this year the bplist was 10x larger again.
In this case it’s fairly clear that the bplist must be a heap groom – and at 5.5MB, presumably a fairly complicated one. So what’s it doing?
Switching Views
I had a hunch that the bplist would use duplicate dictionary keys as a fundamental building block for the heap groom, but running my parser it didn’t output any… until I realised that my tool stored the parsed dictionaries directly as python dictionaries before dumping them. Fixing the tools to instead keep lists of keys and values it became clear that there were duplicate keys. Lots of them:
In the Safari exploit writeup I described how I used different visualisation techniques to try to explore the structure of the objects, looking for patterns I could use to simplify what was going on. In this case, modifying the parser to emit well-formed curly brackets and indentation then relying on VS Code‘s automatic code-folding proved to work well enough for browsing around and getting a feel for the structure of the groom object.
Sometimes the right visualisation technique is sufficient to figure out what the exploit is trying to do. In this case, where the primitive is a heap-based buffer overflow, the groom will inevitably try to put two things next to each other in memory and I want to know “what two things?”
But no matter how long I stared and scrolled, I couldn’t figure anything out. Time to try something different.
Instrumentation
I wrote a small helper to load the bplist using the same API as the MakerNote parser and ran it using the Mac Instruments app:
Parsing the single 5.5MB bplist causes nearly half a million allocations, churning through nearly a gigabyte of memory. Just looking through this allocation summary it’s clear there’s lots of CFString and CFData objects, likely used for heap shaping. Looking further down the list there are other interesting numbers:
The 20’000 in the last line is far too round a number to be a coincidence. This number matches up with the number of __NSDictionaryM objects allocated:
Finally, at the very bottom of the list there are two more allocation patterns which stand out:
There are two sets of very large allocations: eighty 1MB allocations and 44 4MB ones.
I modified my bplist tool again to dump out each unique string or data buffer, along with a count of how many times it was seen and its hash. Looking through the file listing there’s a clear pattern:
Object Size |
Count |
0x3FFFFF |
44 |
0xFFFFF |
80 |
0x3FFF |
20 |
0x26A9 |
24978 |
0x2554 |
44 |
0x23FF |
5822 |
0x22A9 |
4 |
0x1FFF |
2 |
0x1EA9 |
26 |
0x1D54 |
40 |
0x17FF |
66 |
0x13FF |
66 |
0x3FF |
322 |
0x3D7 |
404 |
0xF |
112882 |
0x8 |
3 |
There are a large number of allocations which fall just below a “round” number in hexadecimal: 0x3ff, 0x13ff, 0x17ff, 0x1fff, 0x23ff, 0x3fff… That heavily hints that they are sized to fall exactly within certain allocator size buckets.
Almost all of the allocations are just filled with zeros or ‘A‘s. But the 1MB one is quite different:
$ hexdump -C 170ae757_80.bin | head -n 20
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…………….|
00000010 00 00 00 00 00 00 00 00 80 26 00 00 01 00 00 00 |………&……|
00000020 1f 00 00 00 00 00 00 00 10 00 8b 56 02 00 00 00 |………..V….|
00000030 b0 c3 31 16 02 00 00 00 60 e3 01 00 00 00 00 00 |..1…..`…….|
00000040 20 ec 46 58 02 00 00 00 00 00 00 00 00 00 00 00 | .FX…………|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…………….|
00000060 00 00 00 00 00 00 00 00 60 bf 31 16 02 00 00 00 |……..`.1…..|
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…………….|
*
000004b0 00 00 00 00 00 00 00 00 10 c4 31 16 02 00 00 00 |……….1…..|
000004c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…………….|
*
000004e0 02 1c 00 00 01 00 00 00 00 00 00 00 00 00 00 00 |…………….|
000004f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…………….|
00000500 00 00 00 00 00 00 00 00 70 80 33 16 02 00 00 00 |……..p.3…..|
00000510 b8 b5 e5 57 02 00 00 00 ff ff ff ff ff ff ff ff |…W…………|
00000520 58 c4 31 16 02 00 00 00 00 00 00 00 00 00 00 00 |X.1………….|
00000530 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…………….|
*
00000550 50 75 2c 18 02 00 00 00 01 00 00 00 00 00 00 00 |Pu,………….|
Further on in the hexdump of the 1MB object there’s clearly an NSExpression payload – this payload is also visible just running strings on the WebP file. Matthias Frielingsdorf from iVerify gave a talk at BlackHat Asia with an initial analysis of this NSExpression payload, we’ll return to that at the end of this blog post.
Equally striking (and visible in the hexdump above): there are clearly pointers in there. It’s too early in the analysis to know whether this is a payload which gets rebased somehow, or whether there’s a separate ASLR disclosure step.
On a slightly higher level this hexdump looks a little bit like an Objective-C or C++ object, though some things are strange. Why are the first 24 bytes all zero? Why isn’t there an isa pointer or vtable? It looks a bit like there are a number of integer fields before the pointers, but what are they? At this stage of the analysis, I had no idea.
Thinking dynamically
I had tried a lot to reproduce the exploit primitives on a real device; I built tooling to dynamically generate and sign legitimate PKPass files that I could send via iMessage to test devices and I could crash a lot, but I never seemed to get very far into the exploit – the iOS version range where the heap grooming works seems to be pretty small, and I didn’t have an exact device and iOS version match to test on.
Regardless of what I tried: sending the original exploits via iMessage, sending custom PKPasses with the trigger and groom, rendering the WebP directly in a test app or trying to use the PassKit APIs to render the PKPass file the best I could manage dynamically was to trigger a heap metadata integrity check failure, which I assumed was indicative of the exploit failing.
(Amusingly, using the legitimate APIs to render the PKPass inside an app failed with an error that the PKPass file was malformed. And indeed, the exploit sample PKPass is malformed: it’s missing multiple required files. But the “secure” PKPass BlastDoor parser entrypoint (PKPassSecurePreviewContextCreateMessagesPreview) is, in this regard at least, less strict and will attempt to render an incomplete and invalid PKPass).
Though getting the whole PKPass parsed was proving tricky, with a bit of reversing it was possible to call the correct underlying CoreGraphics APIs to render the WebP and also get the EXIF/MakerNote parsed. By then setting a breakpoint when the huffman tables were allocated I had hoped it would be obvious what the overflow target was. But it was actually totally unclear what the following object was: (Here X3 points to the start of the huffman tables which are 0x3000 bytes large)
(lldb) x/6xg $x3+0x3000
0x112000000: 0x0000000111800000 0x0000000000000000
0x112000010: 0x00000000001a1600 0x0000000000000004
0x112000020: 0x0000000000000001 0x0000000000000019
The first qword (0x111800000) is a valid pointer, but this is clearly not an Objective-C object, nor did it seem to look like any other recognizable object or have much to do with either the bplist or WebP. But running the tests a few times, there was a curious pattern:
(lldb) x/6xg $x3+0x3000
0x148000000: 0x0000000147800000 0x0000000000000000
0x148000010: 0x000000000019c800 0x0000000000000004
0x148000020: 0x0000000000000001 0x0000000000000019
The huffman table is 0x2F28 bytes, which the allocator rounds up to 0x3000. And in both of those test runs, adding the allocation size to the huffman table pointer yielded a suspiciously round number. There’s no way that’s a coincidence. Running a few more tests the table+0x3000 pointer is always 8MB aligned. I remembered from some presentations on the iOS userspace allocator I’d read that 8MB is a meaningful number. Here’s one from Synaktiv:
8MB is the size of the iOS userspace default allocator’s small rack regions. It looks like they might be trying to groom the allocator not to target application-specific data but allocator metadata. Time to dive into some libmalloc internals!
libmalloc
I’d suggest reading the two presentations linked above for a good overview of the iOS default userspace malloc implementation. Libmalloc manages memory on four levels of abstraction. From largest to smallest those are: rack, magazine, region and block. The size split between the tiny, small and large racks depends on the platform. Almost all the relevant allocations for this exploit come from the small rack, so that’s the one I’ll focus on.
Reading through the libmalloc source I noticed that the region trailer, whilst still called a trailer, has been now moved to the start of the region object. The small region manages memory in chunks of 8MB. That 8MB gets split up in to (for our purposes) three relevant parts: a header, an array of metadata words, then blocks of 512 bytes which form the allocations:
The first 0x28 bytes are a header where the first two fields form a linked-list of small regions:
typedef struct region_trailer {
struct region_trailer *prev;
struct region_trailer *next;
unsigned bytes_used;
unsigned objects_in_use;
mag_index_t mag_index;
volatile int32_t pinned_to_depot;
bool recirc_suitable;
rack_dispose_flags_t dispose_flags;
} region_trailer_t;
The small region manages memory in units of 512 bytes called blocks. On iOS allocations from the small region consist of contiguous runs of up to 31 blocks. Each block has an associated 16-bit metadata word called a small meta word, which itself is subdivided into a “free” flag in the most-significant bit, and a 15-bit count.
To mark a contiguous run of blocks as in-use (belonging to an allocation) the first meta word has its free flags cleared and the count set to the number of blocks in the run. On free, an allocation is first placed on a lookaside list for rapid reuse without freeing. But once an allocation really gets freed the allocator will attempt to greedily coalesce neighbouring chunks. While in-use runs can never exceed 31 blocks, free runs can grow to encompass the entire region.
The groom
Below you can see the state of the meta words array for the small region directly following the one containing the huffman table as its last allocation:
(lldb) x/200wh 0x148000028
0x148000028: 0x0019 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x148000038: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x148000048: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x148000058: 0x0000 0x0003 0x0000 0x0000 0x0018 0x0000 0x0000 0x0000
0x148000068: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x148000078: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x148000088: 0x0000 0x0000 0x0000 0x0000 0x0003 0x0000 0x0000 0x001c
0x148000098: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x1480000a8: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x1480000b8: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x1480000c8: 0x0000 0x0000 0x0000 0x001d 0x0000 0x0000 0x0000 0x0000
With some simple maths we can convert indexes in the meta words array into their corresponding heap pointers. Doing that it’s possible to dump the memory associated with the allocations shown above. The larger 0x19, 0x18 and 0x1c allocations all seem to be generic groom allocations, but the two 0x3 block allocations appear more interesting. The first one (with the first metadata word at 0x14800005a, shown in yellow) is the code_lengths array which gets freed directly after the huffman table building fails. The blue 0x3 block run (with the first metadata word at 0x148000090) is the backing buffer for a CFSet object from the MakerNote and contains object pointers.
Recall that the corruption primitive will write the dword 0x270007 0x58 bytes off the end of the 0x3000 allocation (and that allocation happens to sit directly in front of this small region). That corruption has the following effect (shown in bold):
(lldb) x/200wh 0x148000028
0x148000028: 0x0019 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x148000038: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x148000048: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x148000058: 0x0007 0x0027 0x0000 0x0000 0x0018 0x0000 0x0000 0x0000
0x148000068: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x148000078: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x148000088: 0x0000 0x0000 0x0000 0x0000 0x0003 0x0000 0x0000 0x001c
0x148000098: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x1480000a8: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x1480000b8: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x1480000c8: 0x0000 0x0000 0x0000 0x001d 0x0000 0x0000 0x0000 0x0000
It’s changed the size of an in-use allocation from 3 blocks to 39 (or from 1536 to 19968 bytes). I mentioned before that the maximum size of an in-use allocation is meant to be 31 blocks, but this doesn’t seem to be checked in every single free path. If things don’t quite work out, you’ll hit a runtime check. But if things do work out you end up with a situation like this:
(lldb) x/200wh 0x148000028
0x148000028: 0x0019 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x148000038: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x148000048: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x00
4 Comments
cedws
It’s always codecs.
I don’t always buy into the $safelanguage cargo cult but come on, it’s apparent that memory unsafe languages are not appropriate for this purpose and desperately need replacing.
TheDong
It feels so ridiculous to me that a total stranger can send an iMessage message to me, including some attachment, and my phone will process that message in the kernel.
How hard would it be for apple to have a setting of "Only receive messages from mutual contacts", and require the stranger to first "request to be added to contacts" (a message which is tightly controlled, and obviously doesn't include a pdf file or webp or whatever), and have the apple imessage server drop all other messages from them until I accept.
Signal has "message requests". iMessage doesn't have "message requests", and receives messages in a unique path which goes through the kernel.
Like, sure the attacker could hit my Mom with a wrench and iMessage me a PDF exploit that way, but I feel like requiring physical access to one of my contact's phones raises the bar significantly over the current state of affairs.
botanical
NSO Group are a terrorist group for hire. This 0-click, 0-day exploit was found targeting civil society. Any one can pay to target journalists, NGOs, politicians. This is why open-source is paramount to security, and having code out in the open.
ipython
I'm sure nobody would think of targeting the national security apparatus of the USG with such an exploit to gain access to… I dunno, their Signal messages?