Nginx Filename Logic Vulnerability (CVE-2013-4547)

中文版本(Chinese version)

Nginx is a web server that can be used as a reverse proxy, load balancer, mail proxy, and HTTP cache. Nginx 0.8.41 through 1.4.3 and 1.5.x before 1.5.7 allows remote attackers to bypass intended restrictions via an unescaped space character in a URI.

This vulnerability is not directly related to code execution. The main cause is the incorrect parsing of request URIs, which leads to incorrect retrieval of user-requested filenames, resulting in privilege bypass and code execution as side effects.

For example, when Nginx matches requests ending with .php, it sends them to fastcgi for parsing. A common configuration looks like this:

location ~ \.php$ {
    include        fastcgi_params;

    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  /var/www/html$fastcgi_script_name;
    fastcgi_param  DOCUMENT_ROOT /var/www/html;
}

Under normal circumstances (with pathinfo disabled), only files with .php extensions are sent to fastcgi for parsing.

However, in the presence of CVE-2013-4547, when we request 1.gif[0x20][0x00].php, this URI matches the regular expression \.php$ and enters this Location block. But after entering, Nginx incorrectly identifies the requested file as 1.gif[0x20] and sets it as the value of SCRIPT_FILENAME to send to fastcgi.

Fastcgi then parses based on the value of SCRIPT_FILENAME, ultimately resulting in a parsing vulnerability. Therefore, we only need to upload a file ending with a space to make PHP parse it.

Here's another example. Many websites restrict backend access to specific IPs:

location /admin/ {
    allow 127.0.0.1;
    deny all;
}

We can request the following URI: /test[0x20]/../admin/index.php. This URI won't match the location pattern /admin/, thus bypassing the IP verification. However, the actual requested file is /test[0x20]/../admin/index.php, which resolves to /admin/index.php, successfully accessing the backend. (This requires having a directory called "test ": this is a Linux system feature. If a directory doesn't exist, even when jumping to the parent directory, it will throw a file not found error. Windows doesn't have this restriction)

References:

Environment Setup

Run the following command to start a Nginx server 1.4.2:

docker compose up -d

After the environment starts, visit http://your-ip:8080/ to see an upload page.

Vulnerability Reproduce

This server uses blacklist validation, and we cannot upload files with .php extensions. We need to exploit CVE-2013-4547. We upload a "1.gif " (note the space at the end):

Visit http://your-ip:8080/uploadfiles/1.gif[0x20][0x00].php, and you'll find that PHP has been parsed:

Note: [0x20] is a space, [0x00] is \0, and these characters don't need to be encoded.