1 Star 0 Fork 16

吴磊磊/rubygem-puma

forked from src-openEuler/rubygem-puma 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
CVE-2023-40175.patch 5.33 KB
一键复制 编辑 原始数据 按行查看 历史
wk333 提交于 2024-04-11 19:09 +08:00 . Update to 5.6.5 and fix CVE-2022-24790,CVE-2023-40175
From 7405a219801dcebc0ad6e0aa108d4319ca23f662 Mon Sep 17 00:00:00 2001
From: Nate Berkopec <nate.berkopec@gmail.com>
Date: Fri, 18 Aug 2023 09:47:23 +0900
Subject: [PATCH] Merge pull request from GHSA-68xg-gqqm-vgj8
Origin: https://github.com/puma/puma/commit/7405a219801dcebc0ad6e0aa108d4319ca23f662
* Reject empty string for Content-Length
* Ignore trailers in last chunk
* test_puma_server.rb - use heredoc, test_cl_and_te_smuggle
* client.rb - stye/RubyCop
* test_puma_server.rb - indented heredoc rubocop disable
* Dentarg comments
* Remove unused variable
---------
Co-authored-by: MSP-Greg <Greg.mpls@gmail.com>
---
lib/puma/client.rb | 23 ++++++++++++++--------
test/test_puma_server.rb | 42 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 56 insertions(+), 9 deletions(-)
diff --git a/lib/puma/client.rb b/lib/puma/client.rb
index e966f995e8..9c11912caa 100644
--- a/lib/puma/client.rb
+++ b/lib/puma/client.rb
@@ -45,7 +45,8 @@ class Client
# chunked body validation
CHUNK_SIZE_INVALID = /[^\h]/.freeze
- CHUNK_VALID_ENDING = "\r\n".freeze
+ CHUNK_VALID_ENDING = Const::LINE_END
+ CHUNK_VALID_ENDING_SIZE = CHUNK_VALID_ENDING.bytesize
# Content-Length header value validation
CONTENT_LENGTH_VALUE_INVALID = /[^\d]/.freeze
@@ -347,8 +348,8 @@ def setup_body
cl = @env[CONTENT_LENGTH]
if cl
- # cannot contain characters that are not \d
- if cl =~ CONTENT_LENGTH_VALUE_INVALID
+ # cannot contain characters that are not \d, or be empty
+ if cl =~ CONTENT_LENGTH_VALUE_INVALID || cl.empty?
raise HttpParserError, "Invalid Content-Length: #{cl.inspect}"
end
else
@@ -509,7 +510,7 @@ def decode_chunk(chunk)
while !io.eof?
line = io.gets
- if line.end_with?("\r\n")
+ if line.end_with?(CHUNK_VALID_ENDING)
# Puma doesn't process chunk extensions, but should parse if they're
# present, which is the reason for the semicolon regex
chunk_hex = line.strip[/\A[^;]+/]
@@ -521,13 +522,19 @@ def decode_chunk(chunk)
@in_last_chunk = true
@body.rewind
rest = io.read
- last_crlf_size = "\r\n".bytesize
- if rest.bytesize < last_crlf_size
+ if rest.bytesize < CHUNK_VALID_ENDING_SIZE
@buffer = nil
- @partial_part_left = last_crlf_size - rest.bytesize
+ @partial_part_left = CHUNK_VALID_ENDING_SIZE - rest.bytesize
return false
else
- @buffer = rest[last_crlf_size..-1]
+ # if the next character is a CRLF, set buffer to everything after that CRLF
+ start_of_rest = if rest.start_with?(CHUNK_VALID_ENDING)
+ CHUNK_VALID_ENDING_SIZE
+ else # we have started a trailer section, which we do not support. skip it!
+ rest.index(CHUNK_VALID_ENDING*2) + CHUNK_VALID_ENDING_SIZE*2
+ end
+
+ @buffer = rest[start_of_rest..-1]
@buffer = nil if @buffer.empty?
set_ready
return true
diff --git a/test/test_puma_server.rb b/test/test_puma_server.rb
index 298e44b439..2bfaf98848 100644
--- a/test/test_puma_server.rb
+++ b/test/test_puma_server.rb
@@ -627,7 +627,7 @@ def test_large_chunked_request
[200, {}, [""]]
}
- header = "GET / HTTP/1.1\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n"
+ header = "GET / HTTP/1.1\r\nConnection: close\r\nContent-Length: 200\r\nTransfer-Encoding: chunked\r\n\r\n"
chunk_header_size = 6 # 4fb8\r\n
# Current implementation reads one chunk of CHUNK_SIZE, then more chunks of size 4096.
@@ -1365,4 +1365,44 @@ def test_rack_url_scheme_user
data = send_http_and_read "GET / HTTP/1.0\r\n\r\n"
assert_equal "user", data.split("\r\n").last
end
+
+ def test_cl_empty_string
+ server_run do |env|
+ [200, {}, [""]]
+ end
+
+ empty_cl_request = "GET / HTTP/1.1\r\nHost: localhost\r\nContent-Length:\r\n\r\nGET / HTTP/1.1\r\nHost: localhost\r\n\r\n"
+
+ data = send_http_and_read empty_cl_request
+ assert_operator data, :start_with?, 'HTTP/1.1 400 Bad Request'
+ end
+
+ def test_crlf_trailer_smuggle
+ server_run do |env|
+ [200, {}, [""]]
+ end
+
+ smuggled_payload = "GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\nHost: whatever\r\n\r\n0\r\nX:POST / HTTP/1.1\r\nHost: whatever\r\n\r\nGET / HTTP/1.1\r\nHost: whatever\r\n\r\n"
+
+ data = send_http_and_read smuggled_payload
+ assert_equal 2, data.scan("HTTP/1.1 200 OK").size
+ end
+
+ # test to check if content-length is ignored when 'transfer-encoding: chunked'
+ # is used. See also test_large_chunked_request
+ def test_cl_and_te_smuggle
+ body = nil
+ server_run { |env|
+ body = env['rack.input'].read
+ [200, {}, [""]]
+ }
+
+ req = "POST /search HTTP/1.1\r\nHost: vulnerable-website.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 4\r\nTransfer-Encoding: chunked\r\n\r\n7b\r\nGET /404 HTTP/1.1\r\nHost: vulnerable-website.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 144\r\n\r\nx=\r\n0\r\n\r\n"
+
+ data = send_http_and_read req
+
+ assert_includes body, "GET /404 HTTP/1.1\r\n"
+ assert_includes body, "Content-Length: 144\r\n"
+ assert_equal 1, data.scan("HTTP/1.1 200 OK").size
+ end
end
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/wu-leilei/rubygem-puma.git
git@gitee.com:wu-leilei/rubygem-puma.git
wu-leilei
rubygem-puma
rubygem-puma
master

搜索帮助