起步

相关的 issue修复 ,从描述来看,这是一个 sprintf 函数引发的缓冲区溢出漏洞。

补丁获取链接:https://python-security.readthedocs.io/vuln/ctypes-buffer-overflow-pycarg_repr.html

复现

使用 3.8.7 进行复现:

17723-5k3bzo7cnt7.png

这个漏洞在 3.8.8 便已修复:

42845-7hdaq2ol18b.png

分析

通过生成的 coredump 文件,查看异常堆栈:

41587-g21ca52uols.png

注意到 Python-3.8.7/Modules/_ctypes/callproc.c :

PyCArg_repr(PyCArgObject *self)
{
    char buffer[256];
    switch(self->tag) {
    ...
    case 'd':
        sprintf(buffer, "<cparam '%c' (%f)>",   // 这行引发异常
            self->tag, self->value.d);          // value.d 的值是 1e300
        break;

变量 buffer 的长度为 256 ,因此长度不够使得 sprintf 的缓冲区溢出,造成内存的破坏。

写个简单的 C 代码复现这个问题:

#include <stdio.h>

int main(int argc, char **argv) {
  char buffer[256];
  char tag = 'd';
  double value = 1e300;
  sprintf(buffer, "<cparam '%c' (%f)>", tag, value);
  return 0;
}

76548-5rjgjymnk48.png

我在中间加了一行 printf("%f\n", value); 再次执行:

68659-wimuo3l4jzj.png

这个长度已经超过 buffer 定义的长度了。double 类型,表示的小数位数能很大,所以至少可以覆盖 300 个字节;如果是 float 类型,就要小的多了。

在新版本之中该问题已经得到修复,已经将 sprintf 换成 PyUnicode_FromFormat

参考链接


陆安
3.2k 声望237 粉丝

宝可梦情怀粉;刀塔手残党;浴室麦霸王。