Last week Microsoft have announced a patch (MS15-034) fixing a major security vulnerability in IIS, Microsoft’s Windows-based web server. This is a big problem for almost anybody running IIS, allowing any user on the internet to crash their servers with extremely little effort, or potentially take complete control of them.
If you’re running an unprotected IIS you should go and either update right now, or disable IIS Kernel Caching (note that this has some serious performance penalties).
Once you’re not, read on and we’ll take a look into how this works and how it’s happened.
The Attack
Information at this stage is limited, and a full exploit for the remote code execution attack isn’t yet available online, but exploits that immediately crash the whole server are. For now we’ll examine the server-crashing exploit, but it’s likely the full exploit is using very similar principles. Example exploit code is very simple and widely available, and is shown below:
wget --header="Range: bytes=18-18446744073709551615" https://server-address/a-file.png
This attack fundamentally works by sending a request containing a ‘range’ header for a large range of a file on the server. Range headers are used by browsers to request only part of a piece of content, not the whole. This is often used when loading sections of a video when streaming video online for example.
The key point is that the end of the range given is the exact maximum value that will fit into a unsigned long (64-bit) value: 18446744073709551615 (2 to the power of 64, minus 1). The first value of the range appears to be only somewhat relevant: if it’s 0 an unpatched server will return a ‘Requested Range Not Satisfiable’ response, rather than outright crashing. Any value greater than 0 but less than the size of the file however will crash a vulnerable server completely.
Over the past few days software engineers have been examining the changes within Microsoft’s patch, to see why exactly this issue occurs. Definitive answers are hard to come by, but it appears that when receiving a range header, memory is allocated to hold the output of the request, at the right size to hold the response for the browser, and during calculation of the size 1 is added to the upper end of the range. Unfortunately, as this is already the maximum value a long can have, it overflows: for an unsigned long 18446744073709551615 + 1 = 0. Until now Microsoft’s code was not checking for this (a big no-no), resulting in a wildly wrong value, which when used later crashes the process (unclear where, but likely to allocate memory). This is not good.
This is made worse still because this code is part of a windows subsystem called HTTP.sys. HTTP.sys is a Windows driver, running a part of the core system itself with unlimited privileges, which is responsible for interpreting HTTP requests and responses, included in the core of Windows for maximum performance.
When HTTP.sys crashes the whole computer comes with it, the machine blue-screens and is broken until you completely reboot it. Game over.