Permalink
Fetching contributors…
Cannot retrieve contributors at this time
62 lines (47 sloc) 2.55 KB

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