摘要
CVE-2023-40889是通过fuzz手段发现的。其相应的payload是一幅扭曲的,不可读的二维码。
使用标准样式的一维条形码是否亦能引发这个漏洞呢?通过分析CVE-2023-40889的引发机制和研究条形码的实现原理和编码过程,并相应修改开源软件zint,最终,生成出可以触发CVE-2023-40889的标准样式一维条形码。
背景
条形码(Barcode)和二维码(QR Code, Quick Response Code)都是用于自动识别和数据采集的技术,它们通过图形表示信息,可以被专门的设备读取并转换为计算机可处理的数据。
条形码是由一组宽度不同、平行排列的条(Bar)和空(Space)组成的标记,这些条和空有不同的反射特性。当扫描器照射到条形码上时,会根据反射回来的光线强度变化来解读出编码的信息。
最常见的是一维条形码(1D Barcode),例如UPC(Universal Product Code)和EAN(European Article Number)。一维条形码只能在一个方向(通常是水平方向)上携带信息,因此信息量相对有限,主要用于标识商品编号等简单信息。
二维码是我们非常熟悉的。它可以在两个维度(水平和垂直)上存储信息,因此能够容纳比传统的一维条形码更多的数据。QR码最初由日本电装公司于1994年发明,目的是为了在汽车制造中追踪零件。相比一维条形码,二维码能存储更多种类的数据,包括URL链接、文本、联系方式等。如今,二维码充斥于我们的生活。
条形码做为外部的数据源,可以被读取并交由计算机处理,那么,它天然可以做为数据载荷,携带恶意数据,攻击计算机系统。这方面比较有名的事件是在2015年PacSec会议中提出的BadBarcode攻击。这种攻击利用了下面的两点:
- 条码扫描器被计算机视为键盘设备。因此,将键盘码编码为条形码,使计算机将扫描结果做为键盘输入处理。
- ADF(Advanced Data Formatting),一种摩托罗拉开发的更高级的数据输入方式。基于ADF规则,条形码变成了代码,可以进行简单的编程。
通过上面的两种技术的支撑,使用条形码进行攻击成为可能。
Zbar
ZBar 是一个开源的条形码扫描套件。它支持多种一维条形码(如EAN、UPC、Code 128等)和二维码(如QR码)。ZBar 的设计旨在提供快速且准确的解码能力,并且易于集成到各种应用中。它可以在多个操作系统上运行,包括 Linux、macOS 和 Windows。
与具有普适性的BadBarcode攻击不同,最近披露的与条形码有关的 CVE 是针对专门的解码软件 zbar 。这个 CVE 在fuzz过程中,能触发 zbar 产生 stack-buffer-overflow。这个 CVE 是通过 fuzz手段发现的。相应的样本载荷呈现为异常的,人类不可读的样子。如下图:
图一
上面这样的二维码是如何导致 zbar 异常,在报告并没有提及。同时,样本奇怪的样子非常让人困惑,上面扭曲的图像也阻碍了研究者对条形码的理解。
所以,本文尝试介绍和分析条形码的编码原理,并生成一个可理解的条形码图像去触发该CVE。
条形码的基本概念
首先,我们需要理解几条条形码的基本概念,这有助于后面,针对性的生成出可理解的条形码。下面列出了一些基本的概念和解释。
- bar: 条形码是由黑白两色的条纹组成。黑色为 bar 。
- space: 白色部分,或者称为空白部分,称为 space。
- module:条纹的单位宽度称为module。条纹中粗的部分其宽度为 module 的整数倍。
GS1 Databar expanded
在后续的代码分析中,我们发现存在问题的代码是在GS1 Databar expanded的解码函数里,而不是在QR code的解析器。生成GS1 Databar expanded条形码就可以引发该CVE。所以,本节先行介绍GS1 Databar expanded条形码。
GS1 DataBar Expanded 是条形码的一种。它是一维条形码,其长度可变。它选择使用 GS1 应用标识符标准 (AI) 编码多达 74 个数字或 41 个字母字符。GS1 DataBar Expanded 变体的开发是为了在主要标识之外编码更多信息,这些信息在零售收银台读取并在其他应用中处理。下图是这种条形码的示例:
图二
GS1 DataBar Expanded遵循《ISO/IEC 24724-2011》标准。关于它的编码算法和处理流程都在这个标准中给予定义。为了本文的目标,我们需要理解下面的概念:
- Left guard。如图二所示,它是条形码的左边界。由一个space和一个bar组成。宽度均为1 module。
- Right guard。如图二所示,它是条形码的右边界,由一个bar和一个space组成。宽度均为1 module。
- Finder pattern: 这个部分是定位图案,是条形码中关键的结构元素。主要用于帮助扫描设备准确地定位和解码符号。它并不表示实际的信息,但在组装条形码时,其有严格的规则限制。它有固定的宽度:15 modules,由5个bar或space组成。根据条形码的长度,Finder pattern有10种不同的模式序列。《ISO/IEC 24724-2011》中的Table 16对这些模式序列做了定义。
- Symbol character(符号字符)是编码后的多个单元。这些符号字符共同组成了能够表示数据信息的完整条形码符号。符号字符之间间隔了Finder pattern,以便于扫描器定位。符号字符有固定的宽度:17 modules,由4个bar,4个space组成。
- Segment。是指条形码符号中的最小可解码单元。每个 segment 包含一个符号字符和相邻的查找模板(search pattern),并且是构成整个条形码的基本组成部分。
- Check character(校验字符) 是一种用于验证条形码数据完整性和准确性的机制。它是一个附加到条形码符号中的特殊字符,通过数学算法计算得出,并且在整个条形码被扫描后用于确认编码数据的正确性。
上面介绍的