时间锁定加密漏洞披露:Go语言AddDate函数整数溢出分析

本文详细分析了Protocol Labs的tlock时间加密工具中存在的安全漏洞。该漏洞源于Go标准库AddDate函数的整数溢出问题,导致未来时间被错误计算为第1轮,使得加密内容可被立即访问。文章包含技术细节、代码示例和修复方案。

发布时间锁定的负责任披露

我们此前曾宣布将进行时间锁定的负责任披露,该披露已于2023年2月23日00:00(CEST)起可访问。先前加密的报告现可在timevault.drand.love解密。

让我们详细解释这一发现。该问题是在我们审计Protocol Labs的时间锁加密时发现的。tlock是提供基于时间加密的命令行工具,这是一个Go程序,实现了tle命令行工具,提供与网站timevault.drand.love类似的功能。例如,要加密一个7年11个月又1天后的文件,可以使用以下命令:

1
2
3
4
5
6
7
$ ./tle -D 7y11m1d -o encrypted.dat msg.txt
$ cat encrypted.dat
age-encryption.org/v1
-> tlock 81988175 7672797f548f3f4748ac4bf3352fc6c6b6468c9ad40ad456a397545c6e2df5bf
h9Dyx8j8c7kUN7aElXFtNgt8S5ZRHFD9NxzPSceVwuyGrRNGXMEx3sFcHQcFdP5T
uSOdCywzK6HidhKh3Z/IMnZsHLPcM4i+I0gpW58/G4Q
--- yG9ANJMk1CblUDXWX4wknXtE5FcbfI+ENgDtS/nyL3c

我们注意到在加密文件中,字符串"tlock"后的值是文件可访问时的Drand轮次数。当前轮次数可在此处查询。因此,程序将持续时间7y11m1d转换为轮次数81988175。我们发现,若向tlock提供过于遥远的未来年份作为参数,会导致加密针对Drand的第1轮,从而使明文可立即访问。以下是该问题的示例:

1
2
3
4
5
6
7
8
9
$ ./tle -D 292277024627y -o encrypted_file data_to_encrypt
$ cat encrypted_file
age-encryption.org/v1
-> tlock 1
7672797f548f3f4748ac4bf3352fc6c6b6468c9ad40ad456a397545c6e2df5bf

hH/Rge2Um1qQVldiRByfg8MftReTkvr36gOlYDNj4jqdMJu3xuUdPsJ+ZDEnFRC8
+814SBSK+1frE6eoPzoATpClIy1jRwlsdStgFW7yHYU
--- ML9Z9pxb8gGuc3Cu8ng3wyZtFENsWA41TrfQhEY3vK0

在此示例中,轮次数被设置为1。问题在于将持续时间转换为轮次数的过程中。函数parseDuration提取年份数字并将其从当前日期中减去:

1
2
3
4
5
6
years, err := strconv.Atoi(pieces[0])
if err != nil {
    return time.Second, fmt.Errorf("parse year duration: %w", err)
}
diff := now.AddDate(years, 0, 0).Sub(now)
return diff, nil

AddDate函数属于Go标准库中的time包,提供日期相关功能。AddDate调用的Date函数中存在整数溢出问题:年份被转换为天数,然后乘以每天秒数,未进行任何检查。若年份数字过大,会导致错误的负结果。以下是该问题的示例:https://go.dev/play/p/Nz3aFaoA2iF。在tlock中,函数RoundNumber(计算与日期关联的轮次数)对此类负结果返回1。

若攻击者能控制输入日期,并诱使服务器加密未来的内容,而结果可立即访问,这可能构成问题。

该问题已向Protocol Labs报告,随后通过提交96b5251ca25e105d241e46bcca30837fc4dcf150在tlock代码中修复。Go语言中已开设问题并提出了补丁,但在当前Go版本(1.20)中仍存在此问题,因此若您的程序在敏感操作中依赖Date函数,请务必小心。

我们很高兴有机会时间锁定加密并披露影响时间锁加密本身的漏洞发现!

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计