Evitar inyección CRLF en Nginx usando $request_uri
¿Qué es la combinación CRLF?
Cuando un navegador envía una solicitud a un servidor web, éste responde con una respuesta que contiene tanto las cabeceras de respuesta HTTP como el contenido real del sitio web, es decir, el cuerpo de la respuesta. Las cabeceras HTTP y la respuesta HTML (contenido del sitio web) están separadas por una combinación específica de caracteres especiales, a saber, un retorno de carro (CR) y un salto de línea (LF). Para abreviar, también se conocen como CR/LF o simplemente CRLF.
El servidor web utiliza la combinación CRLF para entender cuándo empieza una nueva cabecera HTTP y cuándo termina otra. El CRLF también puede indicar a una aplicación web o a un usuario que comienza una nueva línea en un archivo o en un bloque de texto. Los caracteres CRLF son un mensaje estándar de HTTP/1.1, por lo que son utilizados por todos los servidores web, incluyendo Apache, Nginx, Microsoft IIS y otros.
Ejemplo de cabeceras y código html.
curl -v http://localhost/ > GET / HTTP/1.1 > Host: localhost > User-Agent: curl/7.79.1 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Server: nginx/1.20.1 < Date: Fri, 05 Nov 2021 12:41:58 GMT < Content-Type: text/html < Content-Length: 612 < Last-Modified: Thu, 10 Jun 2021 22:34:09 GMT < Connection: keep-alive < ETag: "60c29361-264" < Accept-Ranges: bytes < <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> * Connection #0 to host localhost left intact
¿Qué es la vulnerabilidad de inyección CRLF?
En un ataque de inyección CRLF, el atacante inserta los caracteres de retorno de carro y salto de línea en la entrada del usuario para engañar al servidor, a la aplicación web o al usuario haciéndole creer que un objeto ha terminado y otro ha comenzado. Aunque las secuencias CRLF no son caracteres maliciosos en sí mismos, pueden utilizarse con intención maliciosa, por ejemplo para dividir la respuesta HTTP.
En las aplicaciones web, una inyección de CRLF puede tener un impacto severo, dependiendo de lo que la aplicación haga con los bloques de solicitud. Las consecuencias pueden ir desde la divulgación de información hasta la ejecución de código, una vulnerabilidad de seguridad de aplicaciones web de impacto directo. No solo a nivel de cabeceras, si no que los logs pueden ser también afectados y se podrían generar logs falsos.
Evitar inyección CRLF en Nginx
En Nginx esto es fácil de resolver, simplemente evitando las variables “$uri” o “$document_uri” en beneficio de “$request_uri”, la cual no interpreta los caracteres CRLF.
Nginx usando $uri / $document_uri
location /test/ { return 302 http://X.X.X.X:8000$uri; }
Test de ineyección CLRF.
curl -v "http://localhost/test/%0d%0aX-TEST:%20CLRF" > GET /test/%0d%0aX-TEST:%20CLRF HTTP/1.1 > Host: localhost > User-Agent: curl/7.79.1 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 302 Moved Temporarily < Server: nginx/1.20.1 < Date: Fri, 05 Nov 2021 12:55:34 GMT < Content-Type: text/html < Content-Length: 145 < Connection: keep-alive < Location: http://X.X.X.X/test/ <-------- < X-TEST: CLRF <-------- INYECCIÒN !! < <html> <head><title>302 Found</title></head> <body> <center><h1>302 Found</h1></center> <hr><center>nginx/1.20.1</center> </body> </html> * Connection #0 to host localhost left intact
Nginx usando $request_uri
location /test/ { return 302 http://X.X.X.X:8000$request_uri; }
Test de inyección CLRF.
curl -v "http://localhost/test/%0d%0aX-TEST:%20CLRF" > GET /test/%0d%0aX-TEST:%20CLRF HTTP/1.1 > Host: localhost > User-Agent: curl/7.79.1 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 302 Moved Temporarily < Server: nginx/1.20.1 < Date: Fri, 05 Nov 2021 12:58:57 GMT < Content-Type: text/html < Content-Length: 145 < Connection: keep-alive < Location: http://X.X.X.X:8000/test/%0d%0aX-TEST:%20CLRF <--------- < <html> <head><title>302 Found</title></head> <body> <center><h1>302 Found</h1></center> <hr><center>nginx/1.20.1</center> </body> </html> * Connection #0 to host localhost left intact