前情提要:畸形二维码点开即崩 微信今晚要加班了
昨晚简单看了一下这个崩溃,因为上下文没有符号,而且函数还挺大,直接放弃了。最关键是对 QRCode 的规范一无所知啊。
看到一些看上去靠谱的分析,转发一下。
GitHub 用户 @GZTimeWalker 放出了一个 PoC,可以构造任意文本内容的 QRCode 让微信崩[1]:
https://gist.github.com/GZTimeWalker/3ca70a8af2f5830711e9cccc73fb5270
PoC 起作用的是最后一段 hack_data,是一段空的 byte segment,并且修改长度属性为 233。
Byte segments 在 zxing 里可以通过 DecoderResult 类的 getByteSegments 方法获取列表[2]。
知乎有人发现这个二维码解析的库已经由微信作为开源项目贡献给了 opencv,可以在 GitHub 上找到对应的源码。
GitHub 上 id 为 @determ1ne 和 @Konano 的用户先后提交了补丁:
https://github.com/opencv/opencv_contrib/pull/3479
https://github.com/opencv/opencv_contrib/pull/3480
这里主要转帖知乎答主[3]的补丁[4]。
补丁主要改了三处:
append 方法中增加一处空指针检查,也是最容易想到的“止血”策略
更深层的原因在于 nBytes 和 count 变量出现了不一致(有点 TOCTOU 的味道)。在 199 行修改了 count,之后又使用了之前 193 行保存的 nBytes
这里还有一个手误的 bug。199 行尝试将 count 的值修正到少于 available / 8 的范围,却写错了运算优先级。语句等价于 count = available
;
有趣的是知乎用户 Lyken 用 ChatGPT 也发现了第三个问题。
这下 AI 抢饭碗了。
这个 bug 中一处笔误造成的长度错误计算造成了一个未初始化的地址解引用,表现就是空指针访问拒绝服务。幸好没有引发直接内存越界读写,否则有可能造成更严重的问题。大名鼎鼎的 FORCEDENTRY 漏洞就靠发送一个畸形的 gif(pdf)实现了代码执行。
而二维码作为一个潜在的社会工程学攻击向量,此前的安全研究一直集中在 URL 打开一个网页来做文章,可能比较少关注到 QRCode 格式自身的解析上来。图像解析一向是模糊测试的重点目标,之后这块代码可能要好好 fuzz 一番了。
本文转载引用的内容没有获得原作者许可,如有侵权,可私信移除。
参考文章
[1]. GZTimeWalker/qrcode_crash_wechat.py
https://gist.github.com/GZTimeWalker/3ca70a8af2f5830711e9cccc73fb5270
[2]. DecoderResult (ZXing 3.5.1 API)
https://zxing.github.io/zxing/apidocs/com/google/zxing/common/DecoderResult.html#getByteSegments--
[3]. 如何评价2023年4月23日晚,微信打开发送图片出现闪退现象
https://www.zhihu.com/question/597372415/answer/2998376458
[4]. fix(wechat_qrcode): Init nBytes after the count value is determined
https://github.com/opencv/opencv_contrib/pull/3480