Nginx SSI Information Disclosure

Stack of rocks
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 HTTP header is defined by RFC2616 as:

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

When Transfer-Encoding: Chunked is in use, each chunked portion of the body must be preceded by it’s length in hexadecimal format followed by a \r\n. The last line of the body should be 0 indicating transfer is complete.

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

The reason this leads to information disclosure is each SSI section of the webpage is proceeded by it’s size which the following example will illustrate. The message body shows fb as the size of the first chunck. Then 6b is used to show the SSI portion while 401 is the length of the remaining body. This makes it clear that the CSS files are being added via SSI.

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

Fixing this is quite easy, simply add the following to the server configuration block.

server {
chunked_transfer_encoding off;
}

Test

Testing can be done using the SocketHttpRequest PowerShell module from my github page: https://github.com/phbits/SocketHttpRequest. Running the following commands will return the raw HTTP response headers and body.

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)"

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store