關於...的一個漏洞

關於...的一個漏洞

一年前,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 的輸入數據,除非有明確的指示並且清楚地了解不需要這樣做。

勘誤

從經驗來看 上一篇文章,為了保持語言的純潔:

錯誤賞金 — 昆蟲狩獵比賽
錯誤報告 - 錯誤通知
重定向 - 重定向
開源 - 開源
勘誤表 - 糾正錯誤

來源: www.habr.com

添加評論