【问题标题】:memcpy overflow boundary exploit? (smashing the stack)memcpy 溢出边界漏洞利用? (粉碎堆栈)
【发布时间】:2011-07-11 07:17:20
【问题描述】:

我试图弄清楚这是否会以某种方式溢出:

void print_address(char *p)
{
  arp_ hw;
  int i;

  hw.length = (size) *(p + _OFFSET1); //189 + 4 = 193
  memcpy(hw.addr, packet + _OFFSET2, hw.length);


  return;
}

其中数据包是从 .txt 文件读取的输入?

【问题讨论】:

  • 您应该将 memcpy 的大小限制为您分配的目的地的预定最大长度。您可能只想简单地拒绝任何更长的警告消息,因为它可能表示攻击尝试,或者网络或源程序出现故障。

标签: c stack overflow


【解决方案1】:

是的,可以溢出;如果数据包中偏移量4处的值大于128,则会溢出hwaddr中的addr字段。

【讨论】:

  • 怎么会大于128?它不是在偏移量 4 处只需要一个字节长度吗?所以长度为 0-9?
  • 无符号字节可以是 0 到 255。
  • 那么在偏移量 4 处产生长度为 255 的字符的示例是什么?
  • @digitalsubdivide:@asveikau 在他们的回答中显示的 \xff 字符(ASCII 值 255)。
【解决方案2】:

hwaddr.len 是一个无符号字符,范围为​​ 0 到 255。因此攻击者可以向您发送一个声明长度为 255 的数据包。由于 hwaddr.addr 被声明为一个 128 字节的缓冲区,因此攻击者可以传递一个有效负载127 字节。够了吗?

通常的 x86 调用约定是推送返回地址,推送参数,然后跳转,此时被调用者将按照声明的顺序分配每个变量。所以,从hwaddr开始算起,hwaddr.len会比栈指针高128字节,packet会高出129字节,返回地址会是129 + sizeof(char *),即使在64位系统。所以,是的,攻击者可以覆盖你的返回地址并额外传递 118 字节的 shell 代码。

编辑我刚刚发现了 OP 的困惑。当您将长度编码为unsigned char 时,这意味着您使用 ASCII 来表示长度。也就是说,你不读这个字节,在上面调用atoi(),得到一个从0到9的个位数。你只需要像一个非常窄的int类型那样使用八位,其中每个位代表一个二进制数字。

【讨论】:

  • 很好的答案。当你说“声明长度 255”不是 (shsize_t) *(packet + _OFFSET1) 只有一个字节吗?所以可以设置 0-9 的长度?
  • 我认为您从根本上误解了 unsigned char 类型的工作方式,但我不知道那是什么。 “0-9 长度”是什么意思?单个字节的范围是 0 到 9?你可以看到这甚至不是二的幂,对吧?
  • 所以在偏移量 4 处我应该使用 \xff 来表示 255 或 11111111?
【解决方案3】:

是的。

例如,如果行以"nnnn\xff" 开头,这将破坏堆栈。

【讨论】:

  • @digitalsubdive - 单步执行代码,很明显。因为memcpy 的第一个参数是一个固定大小的缓冲区。第三个参数是根据用户输入确定的。这是一个非常大的危险信号,是你应该永远做的事情。
【解决方案4】:

当然。你甚至从不检查输入缓冲区是否足够大。

【讨论】:

    【解决方案5】:

    让我大吃一惊的是:

    #define _LENGTH 128
    ...
    typedef struct{
        char addr[_LENGTH];
    ...
    

    后来:

    hwaddr.len = (shsize_t) *(packet + _OFFSET1); //189 + 4 = 193
    memcpy(hwaddr.addr, packet + _OFFSET2, hwaddr.len);
    

    这似乎很危险。您只为 addr 分配了 128 个字节,并且尚未检查以验证复制的信息长度是否为

    当您知道传入数据的长度(如果可能)或检查以确保您没有将额外数据复制到 addr char 数组中时,您可能希望动态分配它:

    if (hwaddr.len <= _LENGTH) {
        memcpy(...);
    }
    

    【讨论】:

      【解决方案6】:

      让我们看看... 您将数据包作为一个字符数组接收,其中第四个字符是数据包的大小。字符是 8 位的,所以当用作无符号数字时,它涵盖了 0-255 的值。您的缓冲区长度设置为 128。这会溢出,您需要对 _LENGTH 进行某种检查。

      【讨论】:

      • 我认为 8 位在 char 上为您提供 0-255 范围。
      猜你喜欢
      • 2012-06-02
      • 2012-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多