关于Microsoft-CrowdStrike蓝屏事件的分析报告
关于Microsoft-CrowdStrike蓝屏事件的分析报告
问题概述
美国时间2024年7月19日下午14:00,全世界采用了微软Windows10 企业版并加装了CrowdStrike公司云安全服务的操作系统发生了大规模的系统崩溃事件,体现为Windows蓝屏,重启无法解决问题。据悉是一位CrowdStrike的临时雇员在一次更新中出现错误导致的,由于属于内核推送,因此重启和网络OTA无法解决问题,导致全世界范围内大量公共服务机构和商业机构面临服务端信息设施崩溃。在IR评级中,本次事故为III级事故,属于严重公共安全事件。
问题原因
技术原因
根据CrowdStrike前雇员Vincent Flibustier的描述,这位开发者在系统中进行了一次优化,据本人描述的代码如下:
1
2
size_t size = static_cast<size_t>(-1);
char* ptr= static_cast<char*>(malloc(size));
上述函数中,-1作为参数通过静态类型转换被强制转到为了无符号size_t,但-1为有符号数,发生了整型溢出,溢出值为SIZE_MAX,malloc函数无法分配如此大的内存,因此返回了空指针。
目前已知CrowdStrike的内核安全产品采用C++编写,从已经发布的样本分析,堆栈显示该后续指针试图以空指针作为基准进行偏移,偏移后的指针访问了内核态的0区间内存空间导致蓝屏。
1
fffff802 1df335a1 458608 mov r9d.dword ptr [r8]ds:0026:00000000'0000009c-????????
在Windows中,MMU如果发现程序访问0区间内存,可以通过触发异常来阻止非法行为,在Windows提供的API中,也有SEH来进行异常捕获,但由于安全软件需要作为系统驱动驻留内存,因此不会被上述安全策略拦截,从内核态直接访问0区间内存是导致蓝屏的直接原因。
设计原因
之所以开发者试图申请如此大的内存,可能的原因有如下两个。
第一个可能的原因是想通过某个值作为哨兵值来确定一个内存基地址,在C++中,有大量的指针往复操作
,例如重载[]运算符来对一个自定义的类型进行索引,但这样的可能性较小,因为开辟空间的行为明确。
第二个可能的原因是这部分内存用于存储某个连续内存地址,例如字符串,但并不清楚字符串的具体长度,因此采用-1作为占位符,而当后续操作通过下标索引运算符进行取值时引发了空指针异常,这个猜测是合理的,因为ptr的类型是明显的char*
如果是其他被擦除类型的对象,开发者更常用于unsigned char*
类型作为一个字节的类型而不是有符号的char
。
至于为何不使用对象的取长度方法或是其他变量,我猜测是实现的函数中没有这个变量的参数,也就是串的本体(例如引用指针或是值)没有传入到函数中,进一步的,因为实现函数没有相关参数,说明这个函数的接口也没有定义这个参数,这属于设计原因。
其他问题
在企业开发中,部署前的测试是最基本的保障,作为微软的合作方,CrowdStrike可能没有进行冒烟测试或是灰度测试,但最基本的测试一定会有,之所以没有被拦截,我猜测有两方面原因:第一个原因是新功能(新函数)没有被测试范围覆盖,由于这是一个临时优化,测试列表中可能尚未添加这个模块,但这个可能不高,能够被推送上线的模块一定要通过测试。
第二个原因是由于接口未给出字符串或对象来源,开发者提出来这个问题,一般是以问题工单进行流转的,在企业内部,这种形式的工单一般属于行政类工单,而代码审计、测试、提交等属于工作流类,在企业级项目中,一般采用分支层次模型,即发布分支是开发分支的父级结构,在commit上看起来可能是时间顺序排列的,但是需要各个分支向主分支合并,同样的,主分支的根节点是发布线,但测试分支与开发分支是兄弟节点,或是在一个层级,在开发中,分支commit向上传播的速度远大于从父节点传播到子节点的速度,因此我们可以猜测,测试门禁的确在模块发布时进行了测试,并且一定是没有通过测试的CI门禁,但由于行政类工单的存在,测试人员不得已把这个门禁加入了白名单,因为这个测试问题一定要引用才能通过,这个行政类工单就是不能通过测试的引用commit,但在部署线上,功能commit已经传播到了发布分支,当发布分支先测试分支进行扩散时,扩散速度远没有门禁快,因为门禁是完全自动化的,而扩散需要手动合并需要测试的代码,因此主管无法得知测试门禁的具体情况,误认为门禁没有报警就意味着可以上线,导致了审查没有通过的代码被推送到了生产环境。
以上仅为猜测,但这种冲突导致的问题在企业级安全产品开发中屡见不鲜,究其原因是因为网络安全行业的特殊性质,在企业安全产品中,CVE预警一经发布,只需要几分钟的时间,试图利用CVE的恶意影响就可以遍布全球,在如此紧张的时间里,安全产品提供方不仅要作出解决方案,还需要进行测试、传播、部署等操作,安全产品提供方几乎没有可能做完整个测试,冒烟测试和灰度测试需要更长时间,更不用说C++驱动在Windows下的编译速度受制于多方面因素,对于任何从事安全产品的公司都是一大挑战,如果因为测试导致发布补丁的时间比利用补丁的时间慢,则用户面临威胁,如果牺牲测试时间换取用户安全,则影响相对较少,即使是大规模蓝屏,造成的综合损失也要比大规模被CVE利用更少,在这样的均衡条件限制下,网络安全公司更倾向于用更快的速度打上及时的补丁以防止被漏洞利用。
2024-7-21
phil616