一个教育性示例,旨在向初学者展示,从一开始就通过逆向工程进行漏洞研究是可能的。
此仓库源于这样一个需求:需要一个简单的示例,用于教授刚起步的漏洞研究初学者,尤其是那些对逆向工程感兴趣的人。
在完成与二进制利用或二进制分析相关的课程、培训或硕士项目后,许多学生认为真正的漏洞研究远远超出了他们的水平。他们通常将逆向工程与非常高级的主题联系起来,如内核漏洞、浏览器利用、固件研究或复杂的现代目标,因此他们认为自己还没有准备好。实际上,问题不在于缺乏知识,而在于缺乏一个现实的起点。
我想要一个示例,能够展示通过基础课程学到的技能,已经可以拿一个真实的程序,理解其工作原理,触发崩溃,并识别出一个真实的漏洞。
此仓库正是这样的示例。它不在于发现复杂的漏洞,而在于展示初学者可以从微小、可重现且可理解的事物开始,并且仍然在进行真正的漏洞研究。
此仓库与我的演讲**"通往首个CVE之路"**直接相关,我在其中解释了进入漏洞研究领域有多种方式,每个人通常会根据自己的兴趣走上不同的道路。
有些人从源代码审计开始,有些人从逆向工程开始,有些人从Web安全开始,还有一些人从技术研究开始。所有这些路径都是有效的,但重要的是要理解每个领域也有适合初学者的切入点。
初学路径的示例包括:
这类目标可能看起来很基础,但它们教授了以后处理复杂系统时所需的相同核心技能。
此仓库代表了逆向工程领域中那些初学者路径之一。
此处记录的漏洞是通过分析一个旧应用程序、理解其文件格式的解析方式,并识别出一个导致崩溃的编程错误而发现的。影响本身并不复杂,但这个过程是真实的、可重现的,并且有助于学习漏洞研究实际是如何进行的。
这正是我在解释"通往首个CVE之路"时使用的示例类型,用以展示逆向工程从一开始就是一条有效的道路,并且从简单目标开始不仅是可接受的,而且通常是学习的最佳方式。
当你刚开始时,现代应用程序往往过于复杂。它们使用了各种保护、缓解措施和代码库,没有大量经验很难理解。旧软件则不同。
遗留应用程序在编写时并未考虑现代安全实践。它们通常包含简单的解析错误、不安全的存储操作和逻辑错误,借助基本的逆向技能即可理解。这使得它们非常适合学习。
使用旧程序,你可以:逆向二进制文件、理解文件格式、触发崩溃、分析崩溃、定位错误、记录问题并报告漏洞。换句话说,你学到了每个漏洞研究人员所需的基本技能。
这正是此示例的意义所在。
此示例之所以重要,是因为它展示了一件非常简单的事情:
如果你喜欢逆向工程,你可以从一开始就沿着这条路走下去。掌握它可能需要数年时间,但你不需要等待数年才能开始做真正的工作。
该漏洞(CVE-2025-70330)影响Easy Grade Pro 4.1在加载专有.EGP成绩册文件时的文件解析逻辑。
应用程序通过从文件中读取固定位置的字段,并将这些值用作已加载文件缓冲区内的偏移量,来重建内部成绩册结构。这些偏移量随后用于计算内存大小并将数据复制到动态分配的缓冲区中。
在正常情况下,文件在继续解析之前会通过多个结构检查。然而,一旦这些检查成功,解析器就会信任文件中存储的偏移量值,而不验证它们是否仍然在已加载缓冲区的边界内。
通过修改原本有效的.EGP文件中的特定字节,可以破坏这些内部偏移计算。当解析器随后使用这些值时,它会尝试在有效文件区域之外读取内存,从而导致访问冲突和应用程序崩溃。
这种情况对应于越界读取(CWE-125),当打开精心构造的文件时,会导致本地拒绝服务。
.EGP文件格式使用基于偏移的方法进行解析。解析器不是顺序处理文件,而是读取包含起始和结束偏移量的内部结构,这些偏移量描述了特定数据块在文件中的位置。
这些偏移量用于计算内存区域的大小,并将数据从已加载的文件缓冲区复制到新分配的内存中。
易受攻击的逻辑可以概括为:
size = offset_end - offset_start + 1
buffer = calloc(1, size)
memcpy(buffer, file_buffer[offset_start - base_offset], size)
一旦文件通过了初始验证检查,解析器就假设文件中存储的偏移量是有效的。没有进行验证以确保计算出的源指针仍然在已加载的文件缓冲区内部。
如果偏移量被以受控方式操纵,解析器可能会尝试读取有效区域之外的内存,从而导致memcpy()操作期间出现访问冲突。
并非每个畸形的.EGP文件都会触发崩溃。
解析器在到达易受攻击的代码路径之前执行多个一致性检查。如果文件结构过于损坏,应用程序会提前停止解析并报告成绩册已损坏。
然而,某些修改使内部结构保持足够的连贯性以通过初始检查,同时仍在后续解析过程中产生不正确的偏移量值。
当这种情况发生时,解析器会到达更深的例程,在这些例程中这些偏移量被信任并用于内存复制操作,最终导致越界读取。
可以通过修改有效的.EGP文件并在特定偏移量处插入受控数据来触发崩溃。
概念验证的工作原理如下:
PoC中使用的示例参数:
此修改使文件结构保持足够有效以通过初始检查,但破坏了解析器后续使用的内部偏移量计算,最终导致应用程序崩溃。
当在调试器下打开畸形文件时,应用程序在内存复制操作期间崩溃。
观察到的异常是由无效内存读取引起的访问冲突。
在调试过程中,memcpy()使用的无效指针源自解析后的文件结构导出的偏移量计算。当这些偏移量引用已加载文件缓冲区之外的内存时,源指针指向一个未映射的地址,导致崩溃。
这证实了该漏洞是由文件解析过程中缺少边界验证引起的。
该漏洞影响一个已生命周期终止的产品,供应商不再对其进行维护。
此问题被记录用于教育和研究目的,并为初学者提供一个具体的例子,展示如何逐步分析软件,以理解错误是如何出现的以及真正的漏洞是如何被发现的。