Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 使用snprintf的缓冲区溢出_C_Buffer - Fatal编程技术网

C 使用snprintf的缓冲区溢出

C 使用snprintf的缓冲区溢出,c,buffer,C,Buffer,这是一项作业,但我的基本理解有问题 易受攻击的代码: int choc(char *arg) { char buf[400]; snprintf(buf, sizeof buf, arg); return 0; } 我知道arg需要是一个格式字符串,它将用我要执行的代码的地址覆盖返回地址。但是我在创建格式字符串时遇到问题 因此,格式字符串需要具备以下内容: 返回指令的地址,我需要覆盖它 %x的列表 我将在返回地址上写入的值。这将是我要执行的代码的地址 为了得到返回地址,我只需要查看

这是一项作业,但我的基本理解有问题

易受攻击的代码:

int choc(char *arg)
{
  char buf[400];
  snprintf(buf, sizeof buf, arg);
  return 0;
}
我知道arg需要是一个格式字符串,它将用我要执行的代码的地址覆盖返回地址。但是我在创建格式字符串时遇到问题

因此,格式字符串需要具备以下内容:

  • 返回指令的地址,我需要覆盖它
  • %x的列表
  • 我将在返回地址上写入的值。这将是我要执行的代码的地址
  • 为了得到返回地址,我只需要查看gdb中'ret'指令的地址,对吗?%x的具体用途是什么?我如何将要执行的代码的地址编码为格式字符串

    我做了一个测试: 使用gdb,我发现我的buf的地址是0xbffffba0。我生成的参数为“\xa0\xfb\xff\xbf\uux.%x.%n”;这不应该在地址0xbffffba0处的buff开始处写入一些值吗?但是我有一个错误。我做错了什么


    任何帮助都将不胜感激

    您试图利用的漏洞称为格式字符串漏洞。
    对于这个主题的进一步研究,我推荐一个名为“黑客:剥削的艺术”的链接或书籍

    从调试器中读取值通常是不够的。一些平台具有地址空间随机化安全特性,这将导致程序调用之间特定对象的地址不同。相反,您需要找出返回地址在堆栈上的存储位置(相对于
    snprintf
    调用),并在那里覆盖它。这是非常特定于CPU的。您开发的平台是什么


    在遇到
    return
    命令之前,使用调试器在程序集级别逐步检查该函数的代码并检查堆栈。确保堆栈和返回地址看起来像您认为应该的样子。这应该会给你一个问题所在的线索。此外,您还可以尝试在返回之前使用调试器手动修改堆栈,以验证您的目标位置实际上是返回地址。

    答案是否,您不仅仅需要“ret”指令的地址。实际上,您需要的是“ret”指令在内存中加载的位置。请看此图:

    您的目标是覆盖“返回地址”

    我将继续写一个简短的程序来显示这个指针(即将出现)

    更新:我有个坏消息。我也不明白。我写过:

    #include <stdio.h>
    #include <stdlib.h>
    
    void bar()
    {
        printf("Bar function\n");
    }
    
    void foo()
    {
        void (**p)(void);
        asm volatile("movl %%ebp, %0\n\t" : "=r"(p) : : "%0");
        p += 1;
        *p = bar;
    }
    
    int main()
    {
        foo();
        return 0;
    }
    
    #包括
    #包括
    空条()
    {
    printf(“条形函数”);
    }
    void foo()
    {
    无效(**p)(无效);
    asm易失性(“movl%%ebp,%0\n\t”:“=r”(p)::%0”);
    p+=1;
    *p=巴;
    }
    int main()
    {
    foo();
    返回0;
    }
    
    这会导致分段错误,而不会在
    栏()中打印句子。
    。我希望它能起作用。。。所以现在我和你一样困惑。有人能解释一下为什么
    bar()
    不在我的代码中执行吗?

    “\xa0\xfb\xff\xbf”
    不应该是buf的地址,而应该是堆栈上返回地址的位置(这是您希望覆盖的值)。您必须使用gdb找到该值


    然后需要在格式字符串中放入足够的%x,以便%n从堆栈中读取该值并写入指定的地址。您还需要使用正确的字段大小,以便%n实际写入正确的值。

    是的,我阅读了该链接。我相信我正在做它要我做的事情。然而,我没有写信给buff,而是收到了一个错误。不确定为什么,我不确定,但您的问题可能与较新版本的linux中内置的一些漏洞利用计数器有关,例如“非可执行堆栈”@Catie-您可能走得太远,导致
    snprintf
    访问堆栈末尾的内存。在组装级别逐步完成该功能,您应该能够看到这是否是问题所在。谢谢!那么返回地址是否保存在%eip中?在gdb中,我做了“info frame”,看到了%eip的保存地址,并创建了一个与上面相同的字符串,只是将该地址交换了一下。总是seg故障。我只是想让它在任何地方都写,没有seg错误(这就是为什么选择buff的开始)。我不想写答案,但我只是做了这个作业。对于那些在我之后的人,我通过一个字节一个字节地覆盖
    \uuu DTOR\uu END\uuu
    使它工作起来。最后,您将使用snprintf调用分配给您的几乎所有字节,但您可以及时这样做并跳转到
    arg
    ,它的末尾应该有您的外壳代码。我按照此链接中解释的第一部分开始: