本文要介绍的漏洞相当特别,是通过导入注册表文件来触发溢出漏洞的。按OSVDB的描述,为“containsanoverflowconditionthatistriggeredasuser-suppliedinputisnotproperlyvalidatedwhenpassedviathe'RegistrationCode'field”。
相信在很多人的印象中,注册表一般是保存配置信息、验证是否注册的地方,谁能想到在这里居然成了一个溢出点!可是请别忘了,注册表也是一串数据,读取注册表也需要用到缓冲区,凭什么就不能溢出呢?先让我们看看相关注册表的结构,入图1所示。
右边共有5个注册表项,其中“Serial”即为“序列号”,这也是触发漏洞的关键——溢出数据的来源——但我们要先寻找的是执行流中的溢出之处。思路是:既然是注册表漏洞,那就先找到相应的API。注册表操作相关的API通常以“Reg”开头,如创建注册表项的RegCreateKeyExA/W、读取注册表项值的RegQueryValueExA/W、写入注册表项值的RegSetValueExA/W,以及关闭注册表操作句柄的RegCloseKey(文中A/W的意思分别指ASCII和宽字符所对应的API)。
OD载入漏洞程序EasyLanFolderShare.exe,想知道程序调用了哪些API,我们可以通过Ctrl+N,找到注册表相关的操作,如图2所示。
从中可以看到,程序调用了几项与注册表相关的API,这里我们只关心读取注册表项值
的RegQueryValueExA,跟进调用该API的地方。
0041A8B2 |. 50 push eax ; |ValueName 0041A8B3 0041A8B6 0041A8B7 |. |. |. 8B4304 50 mov eax,dwordptr[ebx+4] ;| push call eax ;|hKey E868440900 004AED24 ; \RegQueryValueExA
运行程序,在到达溢出点前,程序会两次调用RegQueryValueExA,等到第二次,也就是函数参数ValueName为“Serial”时,单步执行API调用,然后对缓冲区,也即函数参数Buffer指向的内存地址下内存访问断点,本例为0x1483288,如图3所示,之后将断在如图4所示的位置。
接着需要跳过旁枝末节,两次Ctrl+F9,让OD自动执行到函数并返回。
00406819 0040681C 0040681F 00406824 00406827 0040682A 0040682F 00406834 00406837 . . . . . . . . . 8D55B4 lea lea edx,dwordptr[ebp-4C] eax,dwordptr[ebp-4] 0049B5DC 8D45FC E8B84D0900 FF4D84 call dec lea ; 0049B5DC 0049B5AC dwordptr[ebp-7C] eax,dwordptr[ebp-4C] edx,2 8D45B4 BA02000000 E8784D0900 FF4D84 mov call dec lea 0049B5AC ; dwordptr[ebp-7C] eax,dwordptr[ebp-48] 8D45B8 0040683A 0040683F 00406844 00406847 . BA02000000 E8684D0900 8B45FC mov call edx,2 . 0049B5AC ; 0049B5AC Here . . mov call eax,dwordptr[ebp-4] 00406B64 E818030000 ; 00406DB7 00406DBA 00406DBC 00406DC1 00406DC3 |. 8B55EC EB05 mov jmp edx,dwordptr[ebp-14] short00406DC1 edx,4B377D eax,eax |. ;00406DC1 |> |> |. BA7D374B00 33C0 mov xor 8BFA mov edi,edx 00406DC5 00406DC8 00406DCE 00406DD0 00406DD2 00406DD4 00406DD6 00406DD8 |. |. |. |. |. |. |. |. 83C9FF or ecx,FFFFFFFF esi,dwordptr[ebp-248] scasbyteptres:[edi] ecx 8DB5B8FDFFFFlea F2:AE F7D1 repne not sub 2BF9 edi,ecx 8BD1 87F7 mov xchg shr edx,ecx edi,esi C1E902 ecx,2 00406DDB 00406DDD |. |. 8BC7 mov rep eax,edi F3:A5 movsdwordptres:[edi],dwordptr[esi]
为什么上文一再提醒需要留意计数单位呢?因为这个特别的漏洞,成因正是读写所用的计数单位不同所致,具体是指字符串长度计算单位不同,一个为scasb,以byte为单位,一个为movsd,以dword,因此实际复制的长度为实际长度的4倍,覆盖了正常的堆栈。也许当时程序员打了个盹,或者手稍微抖了一下,将b写d,但就是这么一个不仔细看都看不出来的疏忽,造成了这个特别的溢出。