Skip to content

[ssrf] Server Side Request Forgery¤

Server Side Request Forgery - attack that forces a server to perform arbitrary requests (from Nginx in our case). It's possible when an attacker controls the address of a proxied server (second argument of the proxy_pass directive).

How can I find it?¤

There are two types of errors that make a server vulnerable: - lack of the internal directive. It is used to point out a location that can be used for internal requests only; - unsafe internal redirection.

Lack of the internal directive¤

Classical misconfiguration, based on lack of the internal directive, that makes SSRF possible:

location ~ /proxy/(.*)/(.*)/(.*)$ {
    proxy_pass $1://$2/$3;
}

An attacker has complete control over the proxied address, that makes sending requests on behalf of Nginx possible.

Unsafe internal redirection¤

Let's say you have internal location in your config and that location uses some request data as proxied server's address.

E.g.:

location ~* ^/internal-proxy/(?<proxy_proto>https?)/(?<proxy_host>.*?)/(?<proxy_path>.*)$ {
    internal;

    proxy_pass $proxy_proto://$proxy_host/$proxy_path ;
    proxy_set_header Host $proxy_host;
}

According to Nginx docs, internal requests are the following:

  • requests redirected by the error_page, index, random_index, and try_files directives;
  • requests redirected by the “X-Accel-Redirect” response header field from an upstream server;
  • subrequests formed by the “include virtual” command of the ngx_http_ssi_module module and by the ngx_http_addition_module module directives;
  • requests changed by the rewrite directive

Accordingly, any unsafe rewrite allows an attacker to make an internal request and control a proxied server's address.

Misconfiguration example:

rewrite ^/(.*)/some$ /$1/ last;

location ~* ^/internal-proxy/(?<proxy_proto>https?)/(?<proxy_host>.*?)/(?<proxy_path>.*)$ {
    internal;

    proxy_pass $proxy_proto://$proxy_host/$proxy_path ;
    proxy_set_header Host $proxy_host;
}

What can I do?¤

There are several rules you better follow when writing such configurations: - use only "internal locations" for proxying; - if possible, forbid user data transmission; - protect proxied server's address: * if the quantity of proxied hosts is limited (when you have S3 or smth), you better hardcode them and choose them with map or do it some other way; * if you can' list all possible hosts to proxy, you should sign the address.