您的位置:首页 > 其它

历史上的重大软件BUG启示录 第6篇---蠕虫“冲击波”

2016-11-24 14:46 295 查看


(图片来源于网络)         RPC(远程过程调用)是一种进程间通讯机制,最初由 Sun 公司提出,目前为 IETF 标准协议。RPC 协议允许一台计算机上的程序执行另一台远程系统上的代码。Windows的RPC服务也是以RPC为基础开发的。
         2003年某个时候,LSD研究小组发现RPC中存在一个缓冲区溢出漏洞:当发送一个特定包时,会导致Windows RPC服务无提示的崩溃掉!
         LSD小组向微软提交了这个漏洞,2003年7月16号,微软发布补丁程序,用于修复这个缓冲区溢出漏洞。
         9天后,也就是2003年7月25日,中国的一个安全研究小组Xfocus发布了利用该漏洞的攻击测试代码(http://www.xfocus.net/vuls/200307/3878.html)。据说,Xfocus小组内成员对微软提供的补丁程序进行了逆向分析,从而发现了漏洞原理以及相应的攻击方法,并将其公之于众。
         26天后,即8月11日,利用RPC漏洞的蠕虫“冲击波”首次在互联网上传播。24小时后,冲击波感染了336000台计算机。截止到8月14日,冲击波已经感染了超过100万台计算机。
         “冲击波”通过TCP/IP进行传播,一旦攻击成功,就会将一个病毒(msblast.exe)传送到对方计算机中进行感染,如果不能感染系统,则使系统操作异常、不停重启、甚至导致系统崩溃。一旦感染成功,该病毒会建立一个远程shell进程“后门”,该后门监听端口4444,从而允许攻击者远程控制被感染的系统。此外,该病毒还会在一个特定时间对微软的系统升级网站(windowsupdate.com)进行拒绝服务攻击,导致该网站堵塞,使用户无法通过该网站升级系统。
         根据保守估算,“冲击波”蠕虫造成的经济损失至少达到5亿美元!
         “冲击波”蠕虫利用的是一个代码逻辑缺陷,问题代码如下所示(这段代码由微软提供):
error_status_t _RemoteActivation( ...,WCHAR *pwszObjectName,...)
{
*phr= GetServerPath(pwszObjectName, &pwszObjectName);
...
}

HRESULT GetServerPath(WCHAR *pwszPath,WCHAR **pwszServerPath)
{
WCHAR*pwszFinalPath = pwszPath;
WCHARwszMaxhineName[MAX_COMPUTTERNAME_LENGTH_FQDN+1];
hr= GetMachineName(pwszPath, wszMachineName);
*pwszServerPath= pwszFinalPath;
}

HRESULT GetMachineName ( WCHAR*pwszPath,
WCHARwszMachineName[MAX_COMPUTTERNAME_LENGTH_FQDN+1])
{
WCHAR*pwszServerName = wszMachineName;
WCHAR*pwszTemp = pwszPath + 2;
while( *pwszTemp != L’\\’ ) /* 这句代码循环结束条件不充分*/
*pwszServerName++=*pwszTemp++;
/*…*/
}
         错误位于第20~21行,我们单独把这两行代码拿出来:
while( *pwszTemp != L’\\’ ) /* 这句代码循环结束条件不充分*/
*pwszServerName++=*pwszTemp++;
         第一行代码使用while循环从一个长字符串中解析主机名字,结束标志为两个反斜杠(‘\\’)。这里有一个逻辑漏洞,while循环的结束条件并不充分,考虑这样一个情况:攻击者故意发送的字符串中如果没有两个反斜杠,会怎样?结果是程序会一直执行代码*pwszServerName++= *pwszTemp++;,但是指针pwszServerName指向的缓冲区有效长度只有MAX_COMPUTTERNAME_LENGTH_FQDN+1个字节,一旦超过这个区段,则发生缓冲区溢出。如果精心设计溢出部分的数据,化数据为指令,就可以利用缓冲区溢出的数据修改PC指针的值,使之指向我们希望执行的代码,提升权限等。
         这个造成至少5亿美元损失的BUG,修复只改了一行代码!修复后的代码如下所示,仅仅对while循环设置了充分的结束条件:
WCHAR *end_addr = pwszServerName+MAX_COMPUTTERNAME_LENGTH_FQDN;
while ((*pwszTemp != L’\\’ )&& (*pwszTemp != L’\0’)
&&(pwszServerName<end_addr)) /*充分终止条件*/
*pwszServerName++=*pwszTemp++;
         编程是一件细致活,容不得一丝疏忽。即便是编写Windows操作系统的那些非常聪明的人,也会在不经意间埋下一颗逻辑炸弹。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: