Nginx SSI Information Disclosure

Stack of rocks

When implementing Server Side Includes (SSI) on nginx 1.16.1, extra bytes were being returned in the responses. While this wouldn’t be noticed when viewed in a webpage, it can provide information disclosure when viewing the raw stream. The extra bytes were caused by Transfer-Encoding: Chunked being used in the HTTP response.

Transfer-Encoding

The Transfer-Encoding general-header field indicates what (if any)
type of transformation has been applied to the message body in order
to safely transfer it between the sender and the recipient. This
differs from the content-coding in that the transfer-coding is a
property of the message, not of the entity.

Transfer-Encoding: Chunked

The following example shows an HTTP response using this technique. The HTTP body begins with 6b indicating the length of the body followed by the terminating 0.

6b
<link rel=”stylesheet” href=”/css/normalize.min.css”>
<link rel=”stylesheet” href=”/css/test.min.css”>
0

Information Disclosure

fb
<!doctype html>
…html header content omitted…
6b
<link rel=”stylesheet” href=”/css/normalize.min.css”>
<link rel=”stylesheet” href=”/css/test.min.css”>
401
…rest of body omitted…
</html>
0

Having this information allows someone to understand the logic of the webpage/webapp and potentially target that portion. While not concerning if SSI is being used to serve static html files. The issue is using SSI for dynamic purposes such as requests to a CGI script or another web application.

Remediation

server {
chunked_transfer_encoding off;
}

Test

Import-Module SocketHttpRequest.psd1
$httpRequest = @'
GET / HTTP/1.0
Host: www.domain.com
'@
$Result = Invoke-SocketHttpRequest -IP 1.1.1.1 -Port 443 -UseTls -HttpRequest $httpRequest -FullResponse
Write-Host "$($Result.response.headers)"
Write-Host "$($Result.response.body)"