Archive for the ‘Apple’ Category

What I’ve Been Doing On My Summer Vacation or, “It has to work; Otherwise gdb wouldn’t”

Timur | July 17th, 2008 | Filed Under: Apple, Uncategorized

An intern expects to be given simple projects, like coffee retrieval, or “Hello, World.” So I’ve been sorely disappointed by Matasano. I have been offered coffee retrieval services by senior engineers and my latest project has been anything but “Hello, World.”

In fact, it’s been more like, “Hello, OS X. Tell me your secrets”.

This is the story of one trial-by-fire project handed to an intern that turned out to be more complicated than anyone expected.

1.

It started with Thomas, innocently enough, handing me some debugger code. It was both C and Ruby, and for Solaris and Win32. He said, “I would like you to port this Win32 Ruby code to OS X.”

“Um, okay.”

At that point I’d just finished learning the basics of Ruby via my previous Matasano project, a database backed HTTP proxy. I knew nothing about debuggers, let alone the low level C library calls I’d need and Ruby bindings to make them work. I know, fun, right?

I started simply and dusted the C off in my head so I could begin to read and understand the code Thomas dumped on me, and perhaps learn how a debugger works and gets used. It took a day or two just to read it. I’d ask the office some fairly basic question about debuggers, and receive in return a much longer response than I’d anticipated. Like a tutorial on the workings of x86 assembly. Eventually, I got to a point where I was almost comfortable with how the C debugger worked.

When staring at C code stopped doing me any good, and writing Ruby code started seeming feasible, I moved on to porting the Ruby code. “How hard could it be?”.

2.

Thomas gave me a starting point. Our Ruby code called directly into C libraries using Win32API and Ruby/DL. We have wrapper libraries that make those C calls look like Ruby library functions. So, for instance, in our Wrap32 library, we have:

# just grab some local memory
    def malloc(sz)
      r = CALLS["msvcrt!malloc:L=L"].call(sz)
      raise WinX.new(:malloc) if r == 0
      return r
    end

We had a small piece of this written for OS X as well. I had to build it out. I started with getpid(), a simple system call I could make sure worked before I moved on to something harder. It worked right away. My confidence was high. I was feeling cocky.

Here I should mention that I’d never worked on a decently large coding project before. This was my first.

Throughout this entire project I’ve been trying to write the entire thing far before I actually write even a single function. So, I had many questions:

  • What was the script implementing the debugger to look like?

  • Was it to be event driven?

  • Did we want objects to represent each process, threads, or to make his lunch for him?

I was overzealous. The team was patient. Thomas said simply, “There is no spoon. You’ll need ptrace() and wait() for the breakpoint insertion and signal catching. Just copy the functionality from the Win32 version.”

3.

An brief word from the team about how debuggers work.

The thing you most want to do with a debugger is set and handle breakpoints. On X86, there are two kinds of breakpoints: hardware and software. You mostly use software breakpoints. They way software breakpoints work is, you pick the place in the program you want to break at, and you replace the instruction at that point with “INT 3″ (conveniently enough, this is just the byte “0xCC”). When the program hits the INT instruction, it generates an interrupt. The OS catches the interrupt and kills the program.

Unless you have a debugger attached. If you have a debugger attached, instead of killing the program, the OS tells the debugger. The debugger then swaps the original instruction back in, “rewinds” the prograam back to it, and resumes execution.

Every OS has debugging features. They boil down to the following four capabilities:

  • Reading and writing the memory of another process (that’s how you swap INT in for instructions to set breakpoints).

  • Catching events from other processes, like breakpoint interrupts.

  • Starting, stopping, and pausing threads inside other processes.

  • Changing the register state in other processes, for instance by moving the EIP register back 1 byte to rewind the INT 3 instruction that just fired.

The best known Unix debugger interface is ptrace(), and it basically does all four of those things for you, along with the wait() call for detecting events. On Win32, any program can read or write from a process it has the right permissions for, even if it isn’t a debugger; the debugger mostly exists to catch interrupts.

4.

Coding the wrappers for ptrace(), wait(), and waitpid() didn’t take too long. Each just takes a few integers and returns an integer. But ptrace works with request codes, like “PEEK” to read memory or “STEP” to single-step the process. I couldn’t test without knowin all the request codes. So, I started reading man pages, poking at code and trying to get my OS X functions to work.

“To the headers!” I cried. But which one and where are they? As I mentioned, I’m a little new to real — as in non-academic — programming. Google worked OK to get the man pages, but didn’t include the request code numeric values, just the names and what they did. Frustrated, I asked for help.

find /usr/include | xargs grep ptrace | less” was the response I got from Thomas. You didn’t know he speaks *nix? He does. Hexadecimal too, from what I’ve heard.

A little reading and some copying later I had the constants I needed, and began to test my ptrace and wait functions. The code wasn’t pretty but it seemed to work. I could attach to a process by PID and wait() for it. Now I just needed to get its registers and I’d be almost done.

It didn’t take long to sketch my code based on the Win32 debugger I was given to start with. Soon I had what I thought was the start of a functional debugger in Ruby, along with a handy explanation of the Ruby way of doing things. Up until that point I’d been trying to do things the C way, passing variables by reference, trying to make the Ruby function call an exact match to the C call, and other things I’d picked up from the C/C++/JAVA I learned in college.

I thought I was doing well. Then I tried to find the OSX equivalent of PTRACE_GETREGS to read the registers from other processes, which is kind of important for debuggers.

5.

Here everything starts to get more complicated.

It turns out Apple, in their infinite wisdom, had gutted ptrace(). The OS X man page lists the following request codes:

  • PT_ATTACH — to pick a process to debug

  • PT_DENY_ATTACH — so processes can stop themselves from being debugged

  • PT_TRACE_ME — so debuggers can launch processes that start debugged

  • PT_CONTINUE — to restart a program after it’s been stopped

  • PT_STEP — to execute just one instruction in the process

  • PT_KILL — to kill the process

  • PT_DETACH — to release the process

No mention of reading or writing memory or registers. Which would have been discouraging if the man page had not also mentioned PT_GETREGS, PT_SETREGS, PT_GETFPREGS, and PT_SETFPREGS in the error codes section. So, I checked ptrace.h. There I found:

  • PT_READ_I — to read instruction words

  • PT_READ_D — to read data words

  • PT_READ_U — to read U area data if you’re old enough to remember what the U area is

  • PT_WRITE_I — and write instructions

  • PT_WRITE_D — and data

  • PT_WRITE_U — and U

  • PT_SIGEXC — and EXC SIGs

  • PT_THUPDATE — and update THs

  • PT_ATTACHEXC — and attach EXCs

There’s one problem solved. I can read and write memory for breakpoints. But I still can’t get access to registers, and I need to be able to mess with EIP.

That’s when I start hearing “It has to work, otherwise gdb wouldn’t”, rather frequently, from more than one person.

Well, ptrace() won’t work for retrieving registers in OS X.

Matasano Secret Intern X referred me to Nemo’s article at uninformed.org. In it, Nemo lays out the Mach kernel calls that replace some of the lost ptrace() functionality. So, I wrote wrappers for:

  • task_for_pid — to find the Mach task of an OS X process

  • mach_task_self — to get my debugger’s task

  • task_threads — to walk the threads inside a task

  • thread_get_state — to get the registers for one of those threads

  • thread_set_state — to change those registers

Since I wasn’t using them natively in C I needed to know more about the usage of each function.

“No problem,” I thought, “I’ll just fire up terminal and… Oh, bloit!” No man pages.

I pored over Nemo’s work, what I could find in the headers, and figured out how to call the functions. Now another problem. The Mach functions take pointers to raw C memory.

The way I was told to handle this was, pack the data I needed into Ruby strings or native numeric types with Ruby/DL. After a long, dark period of messing with calls to “strdup” and “DL.malloc”, I found “String#to_ptr”, and at last managed to get the Mach functions working.

I had also found the correct way to get errno through Ruby/DL: DL.last_error. This appears to be documented nowhere in English.

Except for an odd bus error I ran into now and then (but couldn’t duplicate), my Ruby debugger was working and could read and write registers. I’d even checked to make sure they were coming back to me in the correct sequence.

Then, running my get_registers() function repeatedly, I found the registers of a stopped process changing on every call. When I printed them without marshalling they contained the names of some of the functions I’d written occasionally.

“Oh, bloit! I’m really chakked now. I’ve been calling a bloitting buffer overflow a register lookup,” I said to myself. I despaired of my project and my future.

6.

On the train home and all weekend I looked through Apple’s documentation. Google. The header files “It has to work; Otherwise gdb wouldn’t,” another friend said. But he wasn’t able to find the documentation I was looking for. He did find fxr.watson.org and some better explanations of the functions at web.mit.edu/darwin/src/modules/xnu/osfmk/man/. Those turned out to be gold later.

During week one of coding:

  • several necessary functions wrapped and working

  • DL.txt is really the only Ruby/DL documentation that exists

  • Ruby/DL is great for simple C function wrapping but rough around the edges when it comes to more interesting calls.

  • Avergage familiarity with Ruby

  • Basic understanding of how a debugger works

  • A Ruby object that can attach to a process, continue it, detach from it and wait() for it.

  • One really convoluted method to read/write random locations in memory

  • Average familiarity with system calls in C (now rust free)

7.

Starting the following week, things went a little smoother.

I had my coding flow going. I had better documentation than just header files. I started reading the Mach kernel code.

I wrote a small program in C to test the sequence of system calls I was using in Ruby. If It worked in C, why didn’t it work in Ruby? Then, I found it. I was calling task_threads() wrong, passing an pointer where it expected a pointer-to-pointer. Whee! I vetted the results with gdb’s output.

My code said:

"regs = ["c0003", "32390", "bffff74c", "90e441ba", "0", "0", "bffff768", "bffff74c", "1f", "286", "90e441ba", "7", "1f", "1f", "0", "37"]"

gdb replied:

eax            0xc0003786435
ecx            0xbffff74c-1073744052
edx            0×90e441ba-1864089158
ebx            0×32390205712
esp            0xbffff74c0xbffff74c
ebp            0xbffff7680xbffff768
esi            0×00
edi            0×00
eip            0×90e441b50×90e441b5
eflags         0×286646
cs             0×77
ss             0×1f31
ds             0×1f31
es             0×1f31
fs             0×00
gs             0×3755

They agreed! I went home for the day.

8.

Now for wait(), to catch debugger events. wait() was hanging the debugger if I called it more than once. I set it up to use the NOHANG option. I fixed an return value error.

Then, I tested single-stepping with ptrace. Kernel panic.

I put that on the list of broken parts of ptrace to be replaced by a Mach call.

Next up was setting breakpoints. They seemed to install themselves without error but the child wasn’t stopping when ran the command that would hit the breakpoint I’d set. Upon inspection, the breakpoint was replacing an instruction of -1. Which gdb told me was actually 0x55.

I started researching the problem, finding only hints. Did I mention ptrace was gutted in OS X? I read the source for Apple’s version of gdb. Thomas gave me a copy of a DTrace truss and said, “Just do whatever gdb does.”

It took me a while to get the script working. It seems iTunes causes errors in truss (also dtruss) whenever it’s running. I closed iTunes and started using watching gdb for ptrace calls. Rather quickly I noticed an extreme lack of call to ptrace.

Was gdb even using ptrace for reading the process’ memory?

(gdb) PID/LWP   SYSCALL(args)  = return
break *0×420f
Breakpoint 1 at 0×420f
(gdb) run
Starting program: /usr/bin/ftp
Reading symbols for shared libraries ++++. done
ftp>   939/94968960:  ptrace(0×0, 0×0, 0×0, 0×0) = 0 0
939/94968960:  ptrace(0xC, 0×0, 0×0, 0×0) = 0 0
930/66961480:  ptrace(0xD, 0×3AB, 0×2C1B, 0×0) = 0 0
930/66961480:  ptrace(0xD, 0×3AB, 0×2C1B, 0×0) = 0 0
930/66961480:  ptrace(0xD, 0×3AB, 0×2C1B, 0×0) = 0 0

It became apparent ptrace was only really used by gdb to:

  • prevent the process from exiting on signals

  • passing signals to the child after it processed them.

I then remembered that uninformed.org article. A quick read reminded me that Mach vm_read and vm_write were needed to replace PT_READ and PT_WRITE.

The next day, Thomas was in the office to check on my progress. To move things along he implemented vm_read and vm_write for me while I confirmed a few things with truss and looked for vm_read calls in gdb. I didn’t find any. When he finished the functions, I used them in my breakpoint setting routines. No errors.

No stopping at breakpoints either.

Again the instructions were -1. When I mentioned this Thomas informed me I’d probably need vm_protect as well. Why hadn’t I thought of that? Not too long after that I was able to set and remove breakpoints correctly! I went home for the long weekend.

During week two of coding:

  • wrapped and implemented all necessary system calls

  • added thread state and breakpoint manipulation to Debuggerx

  • gained some knowledge of OS X internals

  • found a repeatable kernel panic

  • learned basic usage of dtrace and gdb

  • learned I tend to overthink my code before writing it

  • began to use irb as a scratch pad for testing functions

9.

Now another problem. You can set a breakpoint with the debugger. You can catch the breakpoint. You can resume the process. But you can’t reset the breakpoint without single stepping: to resume the process, you have to clear the breakpoint.

But PT_STEP was panicking the kernel!

I settled on setting the TRAP flag in the EFLAGS register to simulate single-stepping with ptrace. This seemed to work. But now I’m getting bus errors when I resume the process. I verified with Thomas how they were supposed to work. I tried watching gdb for vm_write from truss again, nothing. After some debugging I discovered waitpid() was clearing the trap flag, which Thomas informed me was correct behavior. Some more monkeying around trying to get it working ate up the rest of the day.

The next day, I was able to pass through a breakpoint and reset it. Only problem was, the breakpoint wasn’t being reset fast enough, it wasn’t done immediately one step after it was hit. After clearing some confusion on my part with Thomas, I decided to try PT_STEP again. It worked and didn’t panic the kernel this time. Finally, I had a debugging tool that was complete!

All that remained was to clean up some debug tracing prints and implement a better method to view the registers. Both fairly simple things completed early the next day.

10.

There it is, the story of the birth of DebuggerX. A “simple” porting task handed to an intern to better his understanding of debuggers and Ruby. During the project I’d become quite familiar with Ruby, learned some OS X internals, found a kernel panic in ptrace, and learned better programming technics. I still tend to overthink my code and “have a hard time believing that you’re supposed to ask programs to do the things it looks like they need to do,” according to Thomas, but I have learned it’s quite a bit easier to try something in code than in your head. Since completion of the project as originally stated, I’ve added calls to get information about a thread and began looking into retrieving a list of function symbols from the process’ file. I’ll make another post about that in the future.

Comment Bubble 43 Comments

Apple Ships SUIDs With AppleScript Dictionaries. Hilarity Ensues.

Thomas Ptacek | June 19th, 2008 | Filed Under: Apple

Item.

FAIL: Got a Mac? Pull up a Terminal and type

osascript -e 'tell app "ARDAgent" to do shell script "whoami"'

Yep, you’re root. ARDAgent is the Apple Remote Desktop agent application. It’s SUID root —- it runs as the superuser, not your user. That means it needs to be careful not to expose features that let its users muck with the system as superuser. ARDAgent has an AppleScript dictionary. One of the entries in that dictionary is “do shell script”.

Item.

This vulnerability takes us back. It’s not SunOS 4.1.3 IFS variable bad. It’s AIX “tprof” bad. It’s a SUID program whose job is to run programs as root for you. It’s “su” without the password. Well played!

Item.

All due respect to the amazing developers at Apple, who make miracles happen every day and restore childlike joy to our lives, but this confirms Dave’s thesis about Apple developers and Unix security: take a large group of C programmers who cut their teeth on the Mac Toolbox APIs and give them “The Unix You Know On The Mac You Love”, and the result is not —- pardon me for suggesting this —- “Safer by Design”.

There’s a crack team of security people at Apple doing an excellent job locking down an extremely complex operating system. But if you’re lining them up against every Apple developer and giving the developer side the “SUID” bit, it’s not a fair fight. It’s whack-a-mole.

Item.

You can fix this with “chmod u-s ARDAgent”, by removing ARDAgent, or by putting “NSEnableApplescript=YES” in the plist for ARDAgent.

Item.

Start looking for other SUIDs with AppleScript dictionaries; rack up the CVE entries now. They’re mostly harmless, after all.

Item.

There, I said it. We don’t care. Really. I didn’t even fix it on my machine. What’s the point?

My sysadmin alter-ego is infamous for messing up servers after install. I like to deploy systems with no SUIDs at all. The ISP I helped run in the ’90s —- EnterAct —- ran without an SUID “passwd” program. Changing passwords is the motivating use case for SUID. You need to be root to edit the password file. On our systems, passwd was a client of a little network service that did the change. I found the FreeBSD 2.1.4 crt0 hole because one of our dev servers got cracked, it had only one SUID that dropped creds 2 lines into “main()”, and where else could the flaw have been? So I feel like, in the course of pissing off my friends and colleagues for going on 15 years now, I’ve built up the credibility to say:

Who cares if someone busts root on your Mac?

It’s a single-user system. I let you in on a Matasano state secret: if you break the “tqbf” account on my laptop, I’m in trouble. If you’re malware and just trying to spread, or redirect my browser to phishing pages, you’re wasting your time with this “root” silliness.

Item.

For once, the Slashdot commentariat seems to be on the ball. Check out these +4’s:

THe thing is, it’s not true that “one of the main security aspects of OS X is that root access is held sacred (as it should be) and malware is assumed to be ‘stopped at the gate’ by that policy”. It’s not. You can protect the OS from the malware, but the malware can still hide, still restart itself after a reboot, and still destroy everything you actually CARE about without root access. And malware can similarly break out of Vista’s jail around IE, and whatever APple does along those lines.

Unfortunately KDE, Qt, X11, Gtk, Gnome, and the whole “let’s make Linux into Windows” desktop hodgepodge that’s layered on top of UNIX[1] is incredibly complex, has many components running with elevated privileges, and while it has fewer exploitation vectors than Windows it’s conceptually more complex than the NeXTstep-derived equivalents in OS X.

“Malware arguably (one of the greatest scourges of modern computing) spreads by just that, local root vulnerabilities”. No, it does not. Most malware doesn’t need root to do most of the things it wants to do. Having root opens up some more possibilities, but it is by now means required.

There are those here, though, who seem intent on writing this off as a non-exploit or trying to explain it away. That’s where a concept known as “Intellectual Honesty” comes into play. You have to be honest with yourself about what you know and do. Viruses are a fact of life on computers and, while Apple is closed architecture (which by its very nature makes it MUCH more secure than other OSes), it’s only a matter of time before real viruses appear for the Apple platform that just won’t be able to be explained away.

Comment Bubble 25 Comments

Excellent Explanation of Leopard’s Firewall Behavior

Thomas Ptacek | November 1st, 2007 | Filed Under: Apple, Uncategorized

Some of Rich Mogull’s new writeup on what the 10.5 firewall does seems to refute Heise’s article: without “stealth mode” enabled, services show up in port scans but can’t actually be used. It’s still a mess.

Rich seems to have the mysterious test case that demonstrates code signing; let’s see if he’ll give us a step-by-step on it!

Comment Bubble 24 Comments

A Quick Data Point On Sandboxes

Thomas Ptacek | November 1st, 2007 | Filed Under: Apple, Uncategorized

Sandboxes are implemented via the “seatbelt” kext. You can run “lipo” on “seatbelt” to extract the i386 kernel module, and and pull it into a disassembler. Ralf and I are doing that now. Here’s what we now know:

Sandboxes are built, at least in part, on the new security/ subsystem of XNU (the source is available for that), which is derived from TrustedBSD (and, presumably, SEDarwin).

The Sandbox/seatbelt policy layer itself is Apple-proprietary, and I don’t think the source is available; more as I figure out more from the binary.

Comment Bubble 3 Comments

The Silly New Mac OS X Trojan or HoHum.A

Dave G. | November 1st, 2007 | Filed Under: Apple

As I am sure most of our readers are aware, there is a new Mac OS X trojan floating around. The authors seem to target users of pornographic websites, and requires full user interaction to install (e.g. allowing the program to run and typing in your administrator password). While it is definitely a sign that the botnet side of Internet crime is beginning to target Mac users, I don’t agree with Gadi Evron who states:

For whoever didn’t hear, there is a Macintosh trojan in-the-wild being dropped, infecting mac users. Yes, it is being done by a regular online gang—itw—it is not yet another proof of concept. The same gang infects Windows machines as well, just that now they also target macs.

http://sunbeltblog.blogspot.com/2007/10/screenshot-of-new-mac-trojan.html http://sunbeltblog.blogspot.com/2007/10/mackanapes-can-now-can-feel-pain-of.html

This means one thing: Apple’s day has finally come and Apple users are going to get hit hard. All those unpatched vulnerabilities from years past are going to bite them in the behind.

I can sum it up in one sentence: OS X is the new Windows 98. Investing in security ONLY as a last resort losses money, but everyone has to learn it for themselves.

It definitely does not mean that one thing. Here are some quick points:

  1. What unpatched vulnerabilities is he referring to?
  2. This didn’t exploit any vulnerabilities. This same exact trojan exists for Windows. It could also be written for just about any OS.
  3. To this day, I am not entirely convinced that it makes sense to invest in security before it costs you.
  4. OSX is NOT the new Windows 98. It is a pretty unfair comparison. We may be critical of some of Apple’s security efforts, but at least we try to be objective.

One thing I would say is that Mac OS X users may not be as battle hardened as Windows users are when it comes to malware. If there is an increase in this style of Dupe-The-User attack, I wonder what the success rates would be.


  1. If you read this blog, you are not the average Mac user.

Comment Bubble 16 Comments

What We’ve Since Learned About Leopard Security Features

Thomas Ptacek | November 1st, 2007 | Filed Under: Apple, Uncategorized

There are over 100 comments accumulated on my last Leopard post. As usual, they’re better than the post itself. Since you’re probably in a hurry, I’ll spare you the effort of poring over them, and instead present our findings to date.

OS X Runtime Stack Security

A commenter asked if Leopard’s compiler included ProPolice. ProPolice (and/or SSP) is a C compiler extension that guards the call stack of a program, injecting tripwires onto the stack that will be set off by buffer overflows.

Leopard gcc ships with stack protection. There’s probably a simple answer about what OS X programs are compiled with it, but the best I can tell you is that some OS X programs appear to use it; you can see for yourself by loading a program in “gdb”, and disassembling some functions. SSP’d functions have an idiosyncratic prologue and call a “check stack” function in their epilogue.

Do we care? Meh. Stack protectors defend against the oldest, easiest-to-find memory corruption errors. You still find stack overflows in obscure enterprise code, or on embedded platforms that are hard to test. Also on AIX. But you’d be a little shocked to find one in privileged OS X code.

OS X Memory Randomization

A commenter asked if the OS X heap and stack were randomized. Stack memory stores the call stack, which in turn stores the sequence of functions and subroutines being used at any given time. Stack memory also stores most of the variables a program knows about when the program is compiled. Heap memory stores dynamic variables, which depend on the programs inputs rather than on the code itself.

I could now waste your time with a discussion of how valuable stack and heap randomization is, but it’s a moot point: the OS X stack and heap don’t appear to be randomized.

Do we care? A little. Heap overflows are relatively common, because dynamic memory usage is always a bit more complicated than stack memory usage.

Library Randomization

An interesting point was made that the Mach-O ABI was inherently hard to randomize. We had noted that even Leopard’s Library Randomization was imperfect, as it kept the dynamic linker (and, as Ralf pointed out, the program text) at an exposed fixed address. Until those problems are fixed, you might as well not randomize. The commenter basically predicts that it will be awhile before this is resolved.

Do we care? Yes, in that Library Randomization is a major advertised security feature of Leopard. If you don’t randomize program text, it is straightforward to exploit memory corruption vulnerabilities.

W^X and Heap Security

Someone posited that the OS X memory model was now W^X. “Write XOR Execute” is an OpenBSD design idiom; it says that if something in memory is writeable, and therefore exposed to memory corruption, it should not at the same time be executable.

The OS X stack has been non-executable for quite a while. The OS X heap remains executable, a fact you can verify with a trivial piece of C code. Someone involved with PaX, the Linux runtime memory security extension, gave test results verifying that, and also showing that both the stack and the heap could be made executable by returning through the BSD “mprotect” system call.

Do we care? Yeah. This is an area where Leopard is noticeably lagging behind Vista. Read Marinescu’s talk at Black Hat; the Vista heap has an intricate protection scheme; Leopard seems to lack anything comparable.

Sandboxes

OS X Sandboxes —- my favorite Leopard feature, one I’ll have more to say about later —- allow users to write policies that firewall the operating system off from different programs. It is possible to use a Sandbox to prevent iChat from running any other programs, or touching any sensitive files.

Sandboxes are apparently enforced by a kernel extension called “seatbelt”. Seatbelt is a cooler name than Sandbox. Seatbelt calls a program called “sandbox-compilerd” from the kernel when a sandboxed program runs. You’d want OS X to be careful with “sandbox-compilerd”, since it consumes complex input (whole Scheme programs) and runs out of the kernel. In GA Leopard, “sandbox-compilerd” is itself sandboxed (wooo a paradox) and runs under your own credentials.

Do we care? We do, but you shouldn’t; this is just trivia.

Sandboxes and Watson’s Vulnerabilities

Sandboxes were inspired by RBAC features in other operating systems, most notably Niels Provos’ OpenBSD Systrace. Systrace has a well-known vulnerability, first documented by Robert Watson and published formally this year at Usenix WOOT. The problem is a classic TOCTTOU (time-of-check-to-time-of-use) race condition. As an example, Systrace goes to look up a file in the filesystem to see if you can touch it. Between the time Systrace OK’s the operation and the kernel actually performs it, you can swap the safe file with a sensitive one. The kernel’s second lookup will return a different result, which Systrace cannot verify.

Nobody (that we know of) has audited OS X Sandboxes for race conditions. It’s hard to know whether they are present. It wouldn’t surprise us either way.

Do we care? No, not really. First, it’s just speculation. Second, I don’t have any evidence that TOCTTOU races in kernel wrappers are ever actually exploited. Right now, someone actively beating OS X Sandboxing is not writing commodity virus programs; you did something to piss them off.

A Brief Interlude

It is taking me longer to write this up than I expected. Sorry!

The Leopard Firewall

The consensus opinion is that it’s a step backwards. Most notably, it doesn’t filter outbound connections. Multiple commenters note that you can get outbound filtering from programs like Little Snitch.

Do we care? We don’t, but our Moms do. Outbound filtering is more valuable than inbound filtering; it catches “phone-home” malware. It’s not that hard to implement, and I’m surprised Leopard doesn’t do it.

Code Signing

Apple says, “Leopard can use digital signatures to verify that an application hasn’t been changed since it was created.” You can create these signatures with the “codesign” tool, verify them on the command line with “codesign -v”, and display them with “codesign -dvv”. To create a key to sign them under, go to Keychain Access, select “Certificate Assistant” from the app menu, and generate a new “Code Signing” certificate.

Code signatures appear to be enforced from the TMSafetyNet kernel extension. I was just wrong about this, thanks Ralf.

Awesome. Two problems, though.

First: I haven’t yet found a place that checks these signatures. I tried Parental Controls and I tried Saved Passwords in Safari, both times testing by corrupting the binary in the same fashion as a virus. Evidently, the only thing “protected” by signatures is the Keychain, and the “protection” means that instead of accessing the Keychain transparently, you get a confirmation dialog that looks substantially similar to a Keychain dialog you probably click through several times a week.

Second: Even if they were validated, you can still inject unsigned libraries into applications when they launch; this is a core feature of the dynamic linker, which you enable with the “DYLDINSERTLIBRARIES” environment variable.

Do we care? It is very, very, very hard to build systems that gain security from code signing. There are like 10 posts, each longer than this one, that could go into explaining why that is. So, our take is, “no”. There was no way this was going to be a straightforward security win for Leopard. You care to the extend that you are irritated with Apple for marketing hyperbole.

Parental Controls

Here’s an interesting one. You can lock down what executables an account can use. “Parental Controls” undersells this feature. Enterprises pay tens of dollars per desktop for aftermarket software to lock down desktops to trusted applications.

I assumed with a name like “Parental Controls” that the threat model was my 8 year old son. It’s not. Parental Controls are enforced in the kernel, which you can demonstrated by allowing an account Terminal.app and nothing else. Parental Controls will keep you from executing arbitrary programs; it’s enforced at execve()!

Here’s where it gets weird.

Terminal.app is not very useful without the several hundred Unix command line tools you invoke Terminal to get access to. And you can run these programs. They aren’t individually allowed or denied; that would be a nightmare to configure.

You can even execute the compiler, and build new programs. But you can’t execute them!

I originally thought, “Eureka! A place to actually witness Code Signing in action!” No such luck. Copy /bin/ls to /tmp (its signature remains intact), and you can’t run it. Copy “hello world”, with no signature, into “/bin” (as root, of course) and you can. This appears to be “trusted path execution” —- programs in certain directories run, others must be individually allowed.

Unfortunately, the feature is broken in the same way Code Signing is. Want to run an arbitrary program under Parental Controls lockdown? Change its “main()” to a GCC “contructor” function, and compile it as a dylib. Then “DYLDINSERTLIBRARIES” it into any allowed program. Your code runs, and has full access to the system.

Do we care? Kind of a lot, yeah. Not that we’re disappointed. Actually, even though we seem to be able to walk past this feature, it works way better than we expected it to; it is one silly flaw away from parity with expensive aftermarket Windows tools. This feature should be fixed, exposed somewhere besides “Parental Controls”, and relabeled “Secure Desktop”.

Comment Bubble 25 Comments

mDNSResponder Tastes Like Burning

Dave G. | July 18th, 2007 | Filed Under: Apple

InfoSecSellout points us to new mDNSResponder flaw that is, as the vuln reasearch community likes to say, wormable. In fact, InfoSecSellout claims to have done just that.

Which, of course, got the folks at McAfee all riled up. They also have older version of InfoSecSellout’s post. They end their post with:

This story prove both things: the first is that Macintosh with Intel is an interesting target. Real outbreaks are more than ever possible. The second is that the lure of money motivates many people more or less scrupulous. It is another cause for concern.

The PowerPC vs. Intel debate is pretty useless. If you can write exploits on x86, ramping up on what you need to know to exploit vulns on PowerPC is trivial. At least, it was when I did it. It isn’t to say that there aren’t any differences, just that they don’t amount to much from a security perspective.

Of course, Intel vs. PPC is neither here nor there. This post is about mDNSResponder, otherwise known as the primary client -> server attack surface on Mac OS X. The firewall lets mDNS traffic through, and while it is unclear whether or not you can reach mDNS if you aren’t on the local subnet, it’s bad either way.

My favorite part of the source code is LegacyNATTraversal.c. Even the name just speaks of potential problems. Legacy… mmm. NATTraversal… mmm.

Other fun parts:

Revision 1.14.2.1 2005/12/12 17:38:40 cheshire Put buffer overflow bug 4151514 back in by order of Program CCC: “Program CCC Denied. This change does not meet the criteria for Chardonnay.”

Revision 1.13 2005/09/07 18:23:05 ksekar Off-by-one overflow in LegacyNATTraversal

Revision 1.9 2004/10/27 02:25:05 cheshire Random memory smashing bug

Lots of uPNP/SOAP message handling. Plenty of unbounded memory copies, and oh yeah, a history of overflows and memory smashing bugs. If I were guessing where mDNSResponder is going to have bugs, it’s in here. But it is nothing more than a guess.

If you want to run mDNSResponder without using the LegacyNATTraversal code, which might have nothing to do with the aforementioned mDNS worm/vuln, apply this patch, provided by Dino Dai Zovi.

Standard disclaimers about this patch apply (including: may do nothing, may protection you form current/future vulns, may cause mDNSresponder to not work, may break support contracts). Also, this patch is unsupported, which is why I didn’t give step by step instructions on how to apply it. Did I mention that this might have nothing to do with InfoSecSellout’s vuln? And that it could break things? and that we aren’t going to support it?

Comment Bubble 14 Comments

Two Different Perspectives On An OS X Kernel Feature

Thomas Ptacek | July 16th, 2007 | Filed Under: Apple, Uncategorized

1 INT. MATASANO OFFICE - EVENING

Just days before Black Hat. THOMAS PTACEK sits, polishing up Blue Pill detection code. Across the room, DAVID GOLDSMITH, resplendent in purple smoking jacket.

THOMAS PTACEK

I love Apple's IOKit.

DAVID GOLDSMITH

Why?

THOMAS PTACEK

Because you can take a physical address, like the high-performance event timers on the LPC bus, and wire them into a userland process. The process can say, "put the HPET at 0x22220000". And it's like, one line of code!

DAVID GOLDSMITH

Yeah, this is what scares the shit out of me about IOKit.

Comment Bubble No Comments

Matasano Does Not Care About iPhone Security

Dave G. | June 20th, 2007 | Filed Under: Apple, Industry Punditry

The fear mongering stories about the iPhone are beginning to pour in. From exploits to execs storing critical data on it, everyone is talking about how the iPhone is going to be the next security nightmare.

Every device that walks into your organization is just another way for data to leave. Laptops, iPods, cell phones, PDAs and even the dreaded Furby have all gone through this same set of concerns.

Yes, somewhere deep inside of every enterprise is a small team of people that have to worry about data management. And yes, everytime something like this comes out, they have to write a bunch of policy blocking it. And then they have to start relaxing that policy as the devices become commonplace.

If you are responsible for keeping data inside of your organization, for the love of everything that is holy, please don’t spend too much time on the iPhone. Allow us to remind you about all of the data breaches that are happening thanks to insecure wireless access points, tape backups disappearing, wrapping your newspapers in customers’ personal financial information, and stolen laptops.

Will the iPhone compound this problem? Slightly.
Will researchers attack the iPhone? You bet.
Will attackers spend a lot of time trying to steal data off of an iPhone? I doubt it.
Will someone run Linux on the iPhone? Sadly, yes.

The person that spends 500$ on their phone will protect it more than the laptop you issued them.

Comment Bubble 18 Comments

Safari vs. Maynor: Dogs and Cats Living Together, Mass Hysteria!

Jeremy Rauch | June 12th, 2007 | Filed Under: Apple, Disclosure

[Interesting Discussion In Comments -daveg]

Its no secret: I’ve advocated “responsible disclosure” for years. I don’t buy that vulnerability research, and discourse about findings, is why there are so many security problems. Keeping our heads in the sand won’t improve the situation.

Apple’s recent release of Safari for Windows spurred people in our community to start looking for its flaws. Great. I say Safari, for all its good qualities (it’s quick, looks nice, and claims to render more accurately than other browsers), hasn’t benefitted from the scrutiny IE or Firefox gets. If people spend time looking at it, finding vulnerabilities, and reporting them back to Apple, we could have something here. That a large portion of its open sourced makes it all the better.

I’ve been finding vulnerabilities for over 10 years. I’ve been frustrated by vendors that resist patching flaws. And I’ve seen serious flaws go unfixed, due solely to vendor apathy, on numerous occasions. I can see how that could make someone question the “responsible” side of disclosure. Are we wasting our time “playing nice” with vendors?

One of the things we codified when we started Matasano was a disclosure code of ethics. Part of it applies today. In spite of the bad vendor experiences we’ve all had, individually and as group, we felt strongly that to research vulnerabilities without keeping vendors in the loop wasn’t something that we could participate in.

In fact, we’ve gone one step further. We won’t release information without a vendor patch being available. We’re just not comfortable deciding how you should manage your risk. I’d like to keep thinking that disclosure is about making software safer, and not just about ego and marketing.

And that’s why, after my blog hiatus/hibernation/avoidance, I’ve decided to post again.

I say, have all the hostility you want towards Apple. Apple may have done Dave Maynor wrong. Dave may be justified in carrying a grudge. I don’t know all of the facts there, and at the moment, it doesn’t look like any of us will. But I hope Dave, and all the other people taking shots into the barrel of fish that is Safari, are going to do their best to deal responsibly with Apple. I’ve found the Apple security folk I’ve met to be well intentioned and concerned, even if they are severely overburdened and understaffed.

But Dave, if you’re not going to keep Apple in the loop, and you are going to harbor secret Safari vulnerabilities that only your company and your customers and whoever your customers talk to and whoever ever manages to break into those customers may be, can I ask a favor? Can you post what your code of ethics is? A lot of us would like to know. We could show a spectrum, from Errata on the “left”, through MoXB, to eEye on the “liberal”, Matasano on the “centrist”, ISS on the “conservative”, and Cisco on the “right wing”.

Comment Bubble 48 Comments

Who We Are

Matasano is a team of internationally respected security experts who have led security efforts at @stake, Microsoft, ISS, Secure Computing, Arbor Networks, Secure Networks, Bloomberg, Sandia Labs, and others. Read more about our team and how we can help you today.