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/20…)。据说,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操作系统的那些非常聪明的人,也会在不经意间埋下一颗逻辑炸弹。

相关阅读

历史上的重大软件BUG启示录 第5篇—AT&T长途电话网瘫痪事件
历史上的重大软件BUG启示录 第4篇—Google的疏忽

作者:朱工
首发博客:https://freertos.blog.csdn.net/article/details/53320168
关注FreeRTOS从基础到高级专栏,即时收取FreeRTOS系列文章。

发表评论

邮箱地址不会被公开。 必填项已用*标注