The Universal Binary of Crashiness

June 9th, 2008 by Joe Ranieri

What would you say to an application that crashes Finder to the point of being useless? One that merely has to be downloaded, and not even run? I present NukeApp.

For those who don’t feel like experiencing this firsthand, the behavior will vary depending on your Safari download settings. If you’ve set it automatically open downloaded files, Safari will crash and the world will be happy. If you have that option turned off, and you open the zip file up in Finder, Finder will enter a crash loop.

View a movie of the experience.


So, on to the technical details. I’ll start off by saying that this binary has been specifically crafted and is not a valid universal binary — it lies horribly about the number of architectures it contains.

Let’s take a look at the stack trace for where it dies (only showing the top few frames):

_LSAddExecutableFormatInfo
_LSAddBundleExecutableInfo
_LSRegisterDirectoryNode
_LSFindOrRegisterBundleNode
_LSCopyInfoForNode
_LSCopyItemInfoForRefInfo

Aha, it’s LaunchServices giving us the trouble! It looks like Finder is asking it for information about the application and LaunchServices is registering the application in its database. From the looks of it, it’s trying to determine the format of the executable. A closer look at the top function reveals that it’s opening the file and reading it in:

movl        0xfffffb08(%ebp),%eax
leal        0xfffffd34(%ebp),%edx
movl        $0x00000200,0x08(%esp)
movl        %edx,0xfffffafc(%ebp)
movl        %edx,0x04(%esp)
movl        %eax,(%esp)
calll       read$UNIX2003

You’ll notice it’s only reading 512 (0×200) bytes. A bit after this it checks the first long in the data to see which type of executable it is - Mach-O, Mach-O 64-bit, PEF, or a fat binary. If we go down the function a bit more, you’ll notice there’s some strings for each arch type (ppc, ppc64, i386, x86_64). So, what it must be doing is looping through each fat_arch that follows the fat_header. However, since we’re getting crashes, it must not be making sure that it stops reading at the end of its buffer.

Here’s an example that suffers the same issue (ignoring endian issues):

int file = open("/path/to/binary")
char buffer[512];
 
read(buffer, sizeof(buffer), file);
 
fat_header *header = buffer;
fat_arch *archs = buffer + sizeof(fat_header);
 
for(int i = 0; i < header->nfat_archs; i++) {
	// do something with archs[i]
}

This situation comes up in a few diferent places… so how do they handle it?:

  • CFBundle restricts nfat_archs count to the most that fits in the buffer
  • the kernel loader returns error if the archs exceed the size of its buffer (one page size)

I’ll also note that this is not exploitable (it ONLY reads 512 bytes into a 512 byte buffer) and occurs in every version of OS X we could lay our hands on (10.4, 10.5, etc). You cannot inject code into Finder, the Dock, or any other process that crashes in this routine. It’s simply a crash.

We reported this to Apple February 28th (radar 5771210), and have received no response.


Post updated June 9th, with video and slightly better explanation.


COMMENTS

7 Responses to “The Universal Binary of Crashiness”

  1. Metal Says:

    I wonder what would happen if someone were to combine this binary with Safari’s eagerness to download file on the desktop without user input (which is not considered a security bug by Apple, and is slated to be fixed around September.)

  2. kL Says:

    Safari (on OS X at least) isn’t so eager to download and unpack .apps, so you can’t “carpet bomb” users with this.

  3. Mark Lee Smith Says:

    The worst you can do with Safari (on OSX) is to download a load of files, and since the Downloads window jumps to the front when a download starts, it can’t be done without the user knowing. Unless you’re dumb enough to launch untrusted applications yourself you’re safe. Even then, as long as you don’t give the application an admin password the application is severally limited in what it can do.

  4. website design Says:

    He’s ridiculously quick to rule out the ability to exploit this. Nothing is “just a crash”.

  5. Ryan Govostes Says:

    website design: I investigated a bit before he made a ruling like this. (”Ridiculously quick” is a few months since Joe discovered it!) It’s doing a memory read to an invalid address, which causes the crash. I’d be surprised if you could do much with that, since there’s not even privilege escalation going on.

  6. Ryan Govostes Says:

    Mark Lee Smith: Not quite. You could form a binary that does this in just a few KB; a user with broadband wouldn’t have time to react to the download window popping up before everything crashes. The program isn’t a trojan or anything like that, it’s just a malformed file that the system tries to read and crashes in doing so.

  7. Joseph Cohen Says:

    I would like to say, congrats. We have issues in Apple’s bug tracking system that are over a year old. Some are quite serious with root level escalation. I feel your pain. :p

Leave a Reply