diff options
author | kazu <kazu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2008-10-14 02:22:46 +0000 |
---|---|---|
committer | kazu <kazu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2008-10-14 02:22:46 +0000 |
commit | 7809a9a1128cb46441f08b35318f7ae33f6ef44b (patch) | |
tree | 01505263c1df1640a380ebc90f806b45238906ed | |
parent | b80cc7b84703b51b31f8bddbab62361f6f36eed0 (diff) | |
download | ruby-7809a9a1128cb46441f08b35318f7ae33f6ef44b.tar.gz ruby-7809a9a1128cb46441f08b35318f7ae33f6ef44b.tar.xz ruby-7809a9a1128cb46441f08b35318f7ae33f6ef44b.zip |
* lib/net/pop.rb: check for invalid APOP timestamp. (CVE-2007-1558)
[ruby-dev:36631]
* test/net/pop/test_pop.rb: ditto.
git-svn-id: http://svn.ruby-lang.org/repos/ruby/trunk@19776 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | lib/net/pop.rb | 2 | ||||
-rw-r--r-- | test/net/pop/test_pop.rb | 132 |
3 files changed, 140 insertions, 1 deletions
@@ -1,3 +1,10 @@ +Tue Oct 14 11:14:26 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com> + + * lib/net/pop.rb: check for invalid APOP timestamp. (CVE-2007-1558) + [ruby-dev:36631] + + * test/net/pop/test_pop.rb: ditto. + Tue Oct 14 09:39:32 2008 Yukihiro Matsumoto <matz@ruby-lang.org> * ruby.c (set_internal_encoding_once): check double contradicted diff --git a/lib/net/pop.rb b/lib/net/pop.rb index a8e998723..7d234c191 100644 --- a/lib/net/pop.rb +++ b/lib/net/pop.rb @@ -870,7 +870,7 @@ module Net @socket = sock @error_occured = false res = check_response(critical { recv_response() }) - @apop_stamp = res.slice(/<.+>/) + @apop_stamp = res.slice(/<[!-~]+@[!-~]+>/) end attr_reader :socket diff --git a/test/net/pop/test_pop.rb b/test/net/pop/test_pop.rb new file mode 100644 index 000000000..c8aa9a83a --- /dev/null +++ b/test/net/pop/test_pop.rb @@ -0,0 +1,132 @@ +require 'net/pop' +require 'test/unit' +require 'digest/md5' + +class TestPOP < Test::Unit::TestCase + def setup + @users = {'user' => 'pass' } + @ok_user = 'user' + @stamp_base = "#{$$}.#{Time.now.to_i}@localhost" + end + + def test_pop_auth_ok + pop_test(false) do |pop| + assert_instance_of Net::POP3, pop + assert_nothing_raised do + pop.start(@ok_user, @users[@ok_user]) + end + end + end + + def test_pop_auth_ng + pop_test(false) do |pop| + assert_instance_of Net::POP3, pop + assert_raise Net::POPAuthenticationError do + pop.start(@ok_user, 'bad password') + end + end + end + + def test_apop_ok + pop_test(@stamp_base) do |pop| + assert_instance_of Net::APOP, pop + assert_nothing_raised do + pop.start(@ok_user, @users[@ok_user]) + end + end + end + + def test_apop_ng + pop_test(@stamp_base) do |pop| + assert_instance_of Net::APOP, pop + assert_raise Net::POPAuthenticationError do + pop.start(@ok_user, 'bad password') + end + end + end + + def test_apop_invalid + pop_test("\x80"+@stamp_base) do |pop| + assert_instance_of Net::APOP, pop + assert_raise Net::POPAuthenticationError do + pop.start(@ok_user, @users[@ok_user]) + end + end + end + + def test_apop_invalid_at + pop_test(@stamp_base.sub('@', '.')) do |pop| + assert_instance_of Net::APOP, pop + e = assert_raise Net::POPAuthenticationError do + pop.start(@ok_user, @users[@ok_user]) + end + end + end + + def pop_test(apop=false) + host = 'localhost' + server = TCPServer.new(host, 0) + port = server.addr[1] + thread = Thread.start do + sock = server.accept + begin + pop_server_loop(sock, apop) + ensure + sock.close + end + end + begin + pop = Net::POP3::APOP(apop).new(host, port) + #pop.set_debug_output $stderr + yield pop + ensure + begin + pop.finish + rescue IOError + raise unless $!.message == "POP session not yet started" + end + end + ensure + server.close + thread.value + end + + def pop_server_loop(sock, apop) + if apop + sock.print "+OK ready <#{apop}>\r\n" + else + sock.print "+OK ready\r\n" + end + user = nil + while line = sock.gets + case line + when /^USER (.+)\r\n/ + user = $1 + if @users.key?(user) + sock.print "+OK\r\n" + else + sock.print "-ERR unknown user\r\n" + end + when /^PASS (.+)\r\n/ + if @users[user] == $1 + sock.print "+OK\r\n" + else + sock.print "-ERR invalid password\r\n" + end + when /^APOP (.+) (.+)\r\n/ + user = $1 + if apop && Digest::MD5.hexdigest("<#{apop}>#{@users[user]}") == $2 + sock.print "+OK\r\n" + else + sock.print "-ERR authentication failed\r\n" + end + when /^QUIT/ + sock.print "+OK bye\r\n" + return + else + sock.print "-ERR command not recognized\r\n" + return + end + end + end +end |