OD: RPC - MS06040 & MS08067

时间:2023-03-08 18:00:08

RPC 漏洞简介

Remote Procedure Call,分布式计算中常用到的技术。两台计算机通信过程可以分为两种形式:一种是数据的交换,另一种是进程间通信。RPC 属于进程间通信。

RPC 就是在程序中调用一个函数(可能需要很大的计算量),而这个函数是在另外一个或多个远程机器上执行,执行完后将结果返回到调用的机器上继续执行后续操作。RPC 调用过程中的网络操作对程序员来说是透明的,只要将接口定义好,RPC 体系会完成网络上建链、握手、验证、传参、返回等细节问题,让程序员更加关注程序算法与逻辑而非网络细节。

比起其他类型的漏洞,RPC 漏洞危害更大,攻击者不需要利用社工来使未 patch 的机器中招,而可以通过 RPC 主动进行攻击。

RPC 系列漏洞往往伴随蠕虫传播,2003 年的 Blaster、2006 年的 Wargbot / Mocbot、2008 年的 Conficker / Downadup / Kido 都 利用了不同的 RPC 漏洞。Wargbot 利用的 MS06040 和 Conficker 利用的 MS08067 时隔两年,但漏洞出现在同一个 RPC 函数中,同一个函数在修复后又出现如此严重的漏洞并不常见。

RPC 编程简介

使用 RPC 编程时首先要定义远程进程的接口 IDL(Interface Description Language)文件,在这个文件里要指定 RPC 的接口信息以及 interface 下的 function 信息。微软的 IDL 叫做 MIDL,是兼容 IDL 标准的。定义好的 IDL 文件接口经过微软的 MIDL 编译器编译后会生成 3 个文件,一个客户端 stub,一个服务端 stub,还有一个 RPC 调用的头文件。其中 stub 负责 RPC 调用过程所有的网络操作细节。

编译 MS06040 接口文件的命令如下:

midl /acf rpc_exp_040.acf rpc_exp_040.idl # vc6. 组件中有 midl 命令

将产生的 rpc_exp_040_s.c、rpc_exp_040_c.c 和 rpc_exp_040.h 添加进工程,并 include "rpc_exp_040.h" 即可。

(作者参考了 samba 上的 Windows 网络编程接口资料才找到相关 IDL 信息)

MS06040 简介

Windows 系统中有一些非常重要的 DLL,如负责 GUI 操作的 user32.dll、负责系统调用和内存操作的 kernel32.dll 与 ntdll.dll,负责网络操作的 netapi32.dll。几乎所有使用 socket 网络的程序都会加载 netapi32.dll。MS06040 指的就是这个 DLL 的导出函数 NetpwPathCanonicalize() 中存在的缓冲区溢出缺陷,而 NetpwPathCanonicalize() 又可以被 RPC 调用。

2006 年 8 月 8 日,微软公布 MS06040 漏洞和补丁,CVE-2006-3439,补丁号为 KB921883,威胁等级为严重。

动态调试

以 Windows 2000 Pro SP4 为例,进行动态调试。Windows 2000 中,netapi32.dll 位于 C:\WINNT\System32\ 下,如果系统已经 patch 过,则原先的漏洞 DLL 会备份到 C:\WINNT\$Nt UninstallKB921883$ 里。

NetpwPathCanonicalize() 是 netapi32.dll 的导出函数,用于格式化网络路径字符串,其原型如下:

 int NetpwPathCanonicalize (
uint16 path[], // [in] path name
uint8 can_path[], // [out] canonicalized path
uint32 maxbuf, // [in] max size of can_path
uint16 prefix[], // [in] path prefix
uint32* pathtype, // [in out] path type
uint32 pathflags, // [in] path flags, 0 or 1
);

这是一个 Unicode 字符串处理函数,大体功能是:如果 prefix 串非空,将 prefix 串与 path 串用 '\' 相连,并复制到 can_path 中,输出串的容量为 maxbuf 字节大小:

prefix + '\' + path => can_path[max_buf]

在路径合并过程中,函数会做各种检查,如 prefix 或 path 长度是否越界、是否符合路径规范,或 can_path 的容量是否够大等,否则函数将退出,并返回相应错误号,例如 ERROR_INVALID_NAME 0x7B,ERROR_INVALID_PARAMETER 0x135,NERR_BufTooSmall 0x84B 等;函数成功则返回 0,并对 pathtype 进行更新。(关于 NetpwPathCanonicalize() 的细节资料很难找到,Google 上也只是在 srvsvc 的接口定义文件 IDL 里看到函数声明。作者主要是通过 IDA 反汇编找到的这些信息。)