关于...的一个漏洞

关于...的一个漏洞

一年前,21 年 2019 月 XNUMX 日, 错误赏金计划 Mail.Ru HackerOne 来了一位非常好的人 错误报告麦克萨尔。 当在返回 HTTP 重定向的 Webmail API 请求之一的 POST 参数中引入零字节 (ASCII 0) 时,在重定向数据中可以看到未初始化的内存片段,其中来自 GET 参数的片段和其他请求的标头同一个服务器。

这是一个严重的漏洞,因为... 请求还包含会话cookie。 几个小时后,进行了临时修复,过滤了零字节(后来证明,这还不够,因为仍然有可能注入 CRLF / ASCII 13, 10,这允许您操纵标头和HTTP 响应的数据,这不太重要,但仍然令人不快)。 同时,问题被转移给安全分析师和开发人员,以查找并消除 bug 的原因。

Mail.ru 邮件是一个非常复杂的应用程序;大量不同的前端/后端组件,包括开源组件(非常感谢所有自由软件开发人员)和内部开发的组件,都可以参与生成响应。 我们设法排除除 nginx 和 openresty 之外的所有组件,并在调用之前定位问题 ngx.req.set_uri() 在 OpenResty 脚本中,其行为不符合预期(通过 GET 参数插入空字节或换行,并在 ngx_http_rewrite_module 中进行重写,根据文档,它的使用方式似乎应该以完全相同的方式工作,将不行)。 消除了可能的后果,尽可能严格地添加过滤,并验证过滤以消除所有可能的向量。 但导致内存内容泄漏的机制仍然是个谜。 一个月后,错误报告已解决并被关闭,而对错误原因的分析则被推迟到更好的时候。

OpenResty是一个非常流行的插件,允许您在nginx内编写Lua脚本,并且在多个Mail.ru项目中使用它,因此问题并没有被认为解决。 一段时间后,他们终于回到了这个问题,以了解真正的原因、可能的后果并为开发人员提出建议。 参与源码挖掘 丹尼斯·丹尼索夫 и 尼古拉·埃尔米什金。 事实证明:

  • 在nginx中,当对用户数据使用rewrite时,某些配置中存在目录遍历(可能还有SSRF)的可能性,但这是一个已知的事实,应该由静态配置分析器检测到 Nginx 放大 и 吉西 来自 Yandex(是的,我们也使用它,谢谢)。 在使用OpenResty时,这个功能很容易被忽略,但这并不影响我们的配置。

    配置示例:

    location ~ /rewrite {
        rewrite ^.*$ $arg_x;
    }
    
    location / {
        root html;
        index index.html index.htm;
    }

    导致

    curl localhost:8337/rewrite?x=/../../../../../../../etc/passwd
    root:x:0:0:root:/root:/bin/bash
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    bin:x:2:2:bin:/bin:/usr/sbin/nologin
    ...

  • Nginx 有一个错误,如果重写行包含空字节,则会导致内存泄漏。 当发出重定向时,nginx 会分配一个与该行的完整长度相对应的新内存缓冲区,但通过一个 line 函数复制该行,其中零字节是行终止符,因此该行仅复制到零字节;缓冲区的其余部分包含未初始化的数据。 详细分析可以查看 这里.

    配置示例(^@零字节)

    
    location ~ /memleak {
        rewrite ^.*$ "^@asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdasdf";
    }
    
    location / {
        root html;
        index index.html index.htm;
    }

    导致
    curl localhost:8337/secret -vv
    ...
    curl localhost:8337/memleak -vv
    ...
    Location: http://localhost:8337/secret
    ...

  • Nginx 保护 GET 参数免遭服务字符注入,并使得在重写中仅使用 GET 参数成为可能。 因此,不可能通过 nginx 中的用户控制参数来利用注入。 POST 参数不受保护。 OpenResty 允许您使用 GET 和 POST 参数,因此当通过 OpenResty 使用 POST 参数时,可以注入特殊字符。

    配置示例:

    location ~ /memleak {
        rewrite_by_lua_block {
            ngx.req.read_body();
            local args, err = ngx.req.get_post_args();
            ngx.req.set_uri( args["url"], true );
        }
    }
    
    location / {
        root html;
        index index.html index.htm;
    }
    

    结果:

    curl localhost:8337 -d "url=secret" -vv
    ...
    curl localhost:8337 -d "url=%00asdfasdfasdfasdfasdfasdfasdfasdf" -vv
    ...
    Location: http://localhost:8337/{...может содержать secret...}
    ...

进一步反应

该问题已报告给 nginx 和 OpenResty 的开发人员,开发人员并不认为该问题是 nginx 的安全 bug,因为在 nginx 本身中,无法通过注入特殊字符来利用该错误,请修复 内存泄漏 于 16 月 4 日发布。 在报告发布后的 18 个月内,OpenResty 没有发生任何变化,尽管人们认为需要 ngx.req.set_uri() 函数的安全版本。 2020年21月XNUMX日我们发布信息,XNUMX月XNUMX日OpenResty发布 版本1.15.8.3,它添加了 URI 验证。

波特威格 написал 好文章,并听取了 OpenResty 和 Nginx 的评论(尽管仅暴露一小部分内存的评论是不正确且具有误导性的,但这是由空字节后面的行的长度决定的,并且在没有明确限制的情况下)长度,可以由攻击者控制)。

那么错误是什么?可以采取哪些措施来防止错误发生?

nginx有bug吗? 是的,确实如此,因为泄漏内存内容在任何情况下都是一个错误。

OpenResty 是否存在错误? 是的,至少 OpenResty 提供的功能的安全性问题还没有被调查和记录。

OpenResty 是否存在配置/使用错误? 是的,因为在没有明确声明的情况下,对所使用功能的安全性做出了未经验证的假设。

以下哪一个漏洞属于可悬赏 10000 美元的安全漏洞? 对于我们来说,这通常并不重要。 在任何软件中,特别是在多个组件的交集处,尤其是由不同项目和开发人员提供的组件中,没有人可以保证其工作的所有功能都是已知的和记录的,并且没有错误。 因此,任何安全漏洞都恰好发生在影响安全的地方。

无论如何,最好的做法是尽可能规范化或限制/过滤进入任何外部模块/API 的输入数据,除非有明确的指示并且清楚地了解不需要这样做。

勘误表

凭经验 上一篇文章,为了保持语言的纯洁性:

错误赏金 — 昆虫狩猎比赛
错误报告 - 错误通知
重定向 - 重定向
开源 - 开源
勘误表 - 纠正错误

来源: habr.com

添加评论