【问题标题】:return to libc works in gdb but not when running alone返回 libc 在 gdb 中有效,但在单独运行时无效
【发布时间】:2010-11-14 14:54:21
【问题描述】:

我正在尝试使用以下简单代码返回 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。

【问题讨论】:

  • 如果你正在玩这样的漏洞利用,你应该关闭地址空间布局随机化以使其更容易。 echo '0' > /proc/sys/kernel/randomize_va_space
  • 你能否提供更多关于你的代码应该做什么的细节?如果它是一个漏洞,正如@R 所暗示的那样,这就像你正在尝试启动一个 shell,是吗?
  • 谢谢大家。首先我已经关闭了 ALSR,我确信系统/退出调用地址是正确的。
  • @Kevin,是的,我正在尝试从 system("/bin/sh") libc 调用启动一个 shell。

标签: c linux gcc gdb libc


【解决方案1】:

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

【讨论】:

  • 这可能是重点。你能详细说明一下吗?谢谢
【解决方案2】:

gdb设置ADDR_NO_RANDOMIZEpersonality(2)方便调试。

【讨论】:

  • 您的意思是说造成崩溃的是 ASLR。但我已经禁用了它。谢谢
  • main 序言的反汇编会很有趣。另外,可以加printf("system=%p exit=%p &p=%p\n", **(void ***)((char *)system + 2), **(void ***)((char *)exit + 2), &p);吗?
【解决方案3】:

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

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

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

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

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

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

【讨论】:

  • 当然这是个坏主意,但这不是这里的问题。
  • cf 我对这个问题的评论,也许我错过了一点 - 使用您的 junk 空间,您不只是在堆栈中创建一些“分配”空间,然后将值放入“垃圾”中[1-3] 然后退出,什么都没做
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多