123 lines
3.6 KiB
Diff
123 lines
3.6 KiB
Diff
From ea7b67981156f3eaee8420bb34c49605573387a5 Mon Sep 17 00:00:00 2001
|
|
From: shugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
|
|
Date: Wed, 8 Jun 2016 07:06:57 +0000
|
|
Subject: [PATCH] Security: backport SMTP injection fix
|
|
|
|
* lib/net/smtp.rb (getok, get_response): raise an ArgumentError when
|
|
CR or LF is included in a line, because they are not allowed in
|
|
RFC5321.
|
|
|
|
https://hackerone.com/reports/137631
|
|
---
|
|
ChangeLog | 6 ++++++
|
|
lib/net/smtp.rb | 9 +++++++++
|
|
test/net/smtp/test_smtp.rb | 47 ++++++++++++++++++++++++++++++++++++++++++++++
|
|
3 files changed, 62 insertions(+)
|
|
|
|
diff --git a/ChangeLog b/ChangeLog
|
|
index ab9a6bf18281..5176d362881b 100644
|
|
--- a/ChangeLog
|
|
+++ b/ChangeLog
|
|
@@ -1,3 +1,9 @@
|
|
+Sun Jun 11 21:25:09 2017 Shugo Maeda <shugo@ruby-lang.org>
|
|
+
|
|
+ * lib/net/smtp.rb (getok, get_response): raise an ArgumentError when
|
|
+ CR or LF is included in a line, because they are not allowed in
|
|
+ RFC5321. https://hackerone.com/reports/137631 [Backport 0827a7e]
|
|
+
|
|
Wed Jul 5 15:55:35 2017 NAKAMURA Usaku <usa@ruby-lang.org>
|
|
|
|
* ext/openssl/ossl_cipher.c: remove the encryption key initialization
|
|
diff --git a/lib/net/smtp.rb b/lib/net/smtp.rb
|
|
index d634274c3ee8..78f2181d2a8b 100644
|
|
--- a/lib/net/smtp.rb
|
|
+++ b/lib/net/smtp.rb
|
|
@@ -926,7 +926,15 @@ def quit
|
|
|
|
private
|
|
|
|
+ def validate_line(line)
|
|
+ # A bare CR or LF is not allowed in RFC5321.
|
|
+ if /[\r\n]/ =~ line
|
|
+ raise ArgumentError, "A line must not contain CR or LF"
|
|
+ end
|
|
+ end
|
|
+
|
|
def getok(reqline)
|
|
+ validate_line reqline
|
|
res = critical {
|
|
@socket.writeline reqline
|
|
recv_response()
|
|
@@ -936,6 +944,7 @@ def getok(reqline)
|
|
end
|
|
|
|
def get_response(reqline)
|
|
+ validate_line reqline
|
|
@socket.writeline reqline
|
|
recv_response()
|
|
end
|
|
diff --git a/test/net/smtp/test_smtp.rb b/test/net/smtp/test_smtp.rb
|
|
index 0edb3419d56e..3bcceb6fc5bb 100644
|
|
--- a/test/net/smtp/test_smtp.rb
|
|
+++ b/test/net/smtp/test_smtp.rb
|
|
@@ -6,6 +6,8 @@
|
|
module Net
|
|
class TestSMTP < Test::Unit::TestCase
|
|
class FakeSocket
|
|
+ attr_reader :write_io
|
|
+
|
|
def initialize out = "250 OK\n"
|
|
@write_io = StringIO.new
|
|
@read_io = StringIO.new out
|
|
@@ -51,5 +53,50 @@ def test_rset
|
|
|
|
assert smtp.rset
|
|
end
|
|
+
|
|
+ def test_mailfrom
|
|
+ sock = FakeSocket.new
|
|
+ smtp = Net::SMTP.new 'localhost', 25
|
|
+ smtp.instance_variable_set :@socket, sock
|
|
+ assert smtp.mailfrom("foo@example.com").success?
|
|
+ assert_equal "MAIL FROM:<foo@example.com>\r\n", sock.write_io.string
|
|
+ end
|
|
+
|
|
+ def test_rcptto
|
|
+ sock = FakeSocket.new
|
|
+ smtp = Net::SMTP.new 'localhost', 25
|
|
+ smtp.instance_variable_set :@socket, sock
|
|
+ assert smtp.rcptto("foo@example.com").success?
|
|
+ assert_equal "RCPT TO:<foo@example.com>\r\n", sock.write_io.string
|
|
+ end
|
|
+
|
|
+ def test_auth_plain
|
|
+ sock = FakeSocket.new
|
|
+ smtp = Net::SMTP.new 'localhost', 25
|
|
+ smtp.instance_variable_set :@socket, sock
|
|
+ assert smtp.auth_plain("foo", "bar").success?
|
|
+ assert_equal "AUTH PLAIN AGZvbwBiYXI=\r\n", sock.write_io.string
|
|
+ end
|
|
+
|
|
+ def test_crlf_injection
|
|
+ smtp = Net::SMTP.new 'localhost', 25
|
|
+ smtp.instance_variable_set :@socket, FakeSocket.new
|
|
+
|
|
+ assert_raise(ArgumentError) do
|
|
+ smtp.mailfrom("foo\r\nbar")
|
|
+ end
|
|
+
|
|
+ assert_raise(ArgumentError) do
|
|
+ smtp.mailfrom("foo\rbar")
|
|
+ end
|
|
+
|
|
+ assert_raise(ArgumentError) do
|
|
+ smtp.mailfrom("foo\nbar")
|
|
+ end
|
|
+
|
|
+ assert_raise(ArgumentError) do
|
|
+ smtp.rcptto("foo\r\nbar")
|
|
+ end
|
|
+ end
|
|
end
|
|
end
|