1

我正在尝试使用以下简单代码返回 libc 技巧:

#define SYSTEM_CALL_ADDR 0xb7ec5e50  /*my system call addr*/
#define EXIT_CALL_ADDR  0xb7ebbb80   /*my exit call addr*/
char shell[] = "/bin/sh";

int main(){
 int* p; 
 p = (int*)&p + 2;
 *p = SYSTEM_CALL_ADDR;

 p = (int*)&p + 3;
 *p = EXIT_CALL_ADDR;

 p = (int*)&p + 4;
 *p = shell;

 return 1;
}

有趣的是,当我运行这个程序时,它以“分段错误”结束,但如果我使用 gdb 调试它并逐步运行它,它完全没问题,生成一个 shell 然后退出程序。有人遇到这种情况吗?或者有人可以指导我如何纠正这个问题吗?先谢谢了。我在 ArchLinux 内核:2.6.33,gcc 4.5.0。

4

3 回答 3

3

gdb 禁用了一些缓冲区溢出漏洞利用缓解技术,例如 ProPolice 和地址空间布局随机化 (ASLR)。

于 2010-11-14T16:28:41.810 回答
1

gdb 设置ADDR_NO_RANDOMIZE 个性(2)以方便调试。

于 2010-11-14T17:03:59.487 回答
0

发生崩溃是因为您声明变量 'p' 仅在堆栈上为单个 (int *) 指针分配了足够的空间,但随后您将值填充到 (&p + 2) 等中,因此您最终会覆盖谁知道-什么。无论是否使用 gdb,它的行为都会有所不同,因为“谁知道”部分在一个环境中可能并不重要,但在另一个环境中却很重要。

您可以通过确保您将要丢弃的空间不是任何重要的东西来“修复”您的程序。

int main(){
 int* p;
 char junk[100];    /* ADD THIS */

现在,为“p”分配的存储空间之后的空间(很可能)是垃圾字符数组,您可以通过覆盖来摆脱它。(当我使用“gcc -O0 -g”编译时,至少可以“修复”我特定 Linux 系统上的程序)。

综上所述——您在那里使用的方法绝不是便携或安全的。编译器不保证它会按照我们声明它们的特定顺序来安排存储分配。此外,使用不同的优化开关进行编译可能会改变行为。因此,虽然这可能是一个有趣的练习,但您当然不应该期望这种方法能够始终如一地工作。

以这种方式手动操作 C 堆栈是一个坏主意!

于 2010-11-14T16:05:52.713 回答