Host Header Injection, and Nginx default config

Just asking this question in the forum to see if anyone has an opinion on it. A client’s site running on Hestia recently had a pentest and one of the items was a fail on the Host Header Injection. I understand that not every item on a pentest is necessarily a red flag, but I decided to look into it. So here’s how to test it

curl -I https://realdomain.onhesita.com/ -H "Host: evil.com"
HTTP/2 301 
server: nginx
date: Fri, 16 Sep 2022 02:54:24 GMT
content-type: text/html
content-length: 162
location: http://evil.com/

So the fact that the location is returned as the evil.com domain means we’ve tricked the webserver into thinking its serving a page that doesn’t even exist on the server. While its hard to exploit, it can have pretty dire consequences, such as being leveraged in password reset attacks.

I started looking for the code where this was taking place. It wasn’t in the individual website templates, but I found the following line in /etc/nginx/nginx.conf which seems to be responsible.

proxy_set_header                Host $host;

Disabling that isn’t an option as then nginx doesn’t know where to send the response for any website. So following the logic, this only becomes a problem when the host is unknown, i.e. when nginx is using the “server_name _;” condition.
This is found in the config file corresponding to the IP address of the server i.e. /etc/nginx/conf.d/23.34.45.56.conf
Disabling that config makes the problem go away .

So, first question: are there any harmful effects of disabling that config? I guess its used in the setup phase, when only the IP address is available, but beyond that, is it actually used? Maybe for nginx-status queries?

Secondly, is there a better way of doing this? All I can think of is using the IP address as hostname in the default config. I’m not one to obsess over every pentest result, but it seems if this can be fixed with low effort then its worth doing.

Been investigating a bit more and thought I’d include the default nginx config /etc/nginx/conf.d/12.23.34.45.conf

#=========================================================================#
# Default Web Domain Template                                             #
# DO NOT MODIFY THIS FILE! CHANGES WILL BE LOST WHEN REBUILDING DOMAINS   #
# https://docs.hestiacp.com/admin_docs/web.html#how-do-web-templates-work #
#=========================================================================#

server {
    listen       12.23.34.45:80 default;
    server_name  _;
    #access_log  /var/log/nginx/12.23.34.45.log main;
    location / {
        proxy_pass  http://12.23.34.45:8080;
   }
}

server {
    listen      12.23.34.45:443 ssl http2;
    server_name _;
    ssl_certificate      /usr/local/hestia/ssl/certificate.crt;
    ssl_certificate_key  /usr/local/hestia/ssl/certificate.key;

    return 301 http://$host$request_uri;

    location / {
        root /var/www/document_errors/;
    }

    location /error/ {
        alias /var/www/document_errors/;
    }
}

OK, so the first thing I notice is that the 301 line also uses the $host variable, so changing it to something else gets rid of the problem:

     #return 301 http://$host$request_uri;
     return 404;

So maybe that’s a solution? Anyway, it looks like the line in the main nginx.conf is not to blame as I originally thought

Second thing I notice, is that on my server I changed the hestia port, so the proxy_pass port is wrongly stated as 8080 in the stanza above.

If ip.conf is the issue I would remove the proxy header in the config file

Yes it should be fine:

return 301 http://$host$request_uri;

Replace it with return 404;