[prev in list] [next in list] [prev in thread] [next in thread] 

List:       oss-security
Subject:    [oss-security] [CVE-2019-5418] File Content Disclosure in Action View
From:       Aaron Patterson <tenderlove () ruby-lang ! org>
Date:       2019-03-13 17:18:42
Message-ID: 20190313171842.GC90773 () TC-275 ! local
[Download RAW message or body]

[Attachment #2 (multipart/mixed)]


There is a possible file content disclosure vulnerability in Action View. This
vulnerability has been assigned the CVE identifier CVE-2019-5418.

Versions Affected:  All.
Not affected:       None.
Fixed Versions:     6.0.0.beta3, 5.2.2.1, 5.1.6.2, 5.0.7.2, 4.2.11.1

Impact
------
There is a possible file content disclosure vulnerability in Action View.
Specially crafted accept headers in combination with calls to `render file:`
can cause arbitrary files on the target server to be rendered, disclosing the
file contents.

The impact is limited to calls to `render` which render file contents without
a specified accept format.  Impacted code in a controller looks something like
this:

```
class UserController < ApplicationController
  def index
    render file: "#{Rails.root}/some/file"
  end
end
```

Rendering templates as opposed to files is not impacted by this vulnerability.

All users running an affected release should either upgrade or use one of the
workarounds immediately.

Releases
--------
The 6.0.0.beta3, 5.2.2.1, 5.1.6.2, 5.0.7.2, and 4.2.11.1 releases are
available at the normal locations.

Workarounds
-----------
This vulnerability can be mitigated by specifying a format for file rendering,
like this:

```
class UserController < ApplicationController
  def index
    render file: "#{Rails.root}/some/file", formats: [:html]
  end
end
```

In summary, impacted calls to `render` look like this:

```
render file: "#{Rails.root}/some/file"
```

The vulnerability can be mitigated by changing to this:

```
render file: "#{Rails.root}/some/file", formats: [:html]
```

Other calls to `render` are not impacted.

Alternatively, the following monkey patch can be applied in an initializer:

```
$ cat config/initializers/formats_filter.rb
# frozen_string_literal: true

ActionDispatch::Request.prepend(Module.new do
  def formats
    super().select do |format|
      format.symbol || format.ref == "*/*"
    end
  end
end)
```

Patches
-------
To aid users who aren't able to upgrade immediately we have provided patches for
the two supported release series. They are in git-am format and consist of a
single changeset.

* 6-0-action-view-file-disclosure.patch - Patch for 6.0 series
* 5-2-action-view-file-disclosure.patch - Patch for 5.2 series
* 5-1-action-view-file-disclosure.patch - Patch for 5.1 series
* 5-0-action-view-file-disclosure.patch - Patch for 5.0 series
* 4-2-action-view-file-disclosure.patch - Patch for 4.2 series

Please note that only the 5.2.x, 5.1.x, 5.0.x, and 4.2.x series are supported
at present. Users of earlier unsupported releases are advised to upgrade as
soon as possible as we cannot guarantee the continued availability of security
fixes for unsupported releases.

Also note that the patches for this vulnerability are the same as CVE-2019-5419.

Credits
-------
Thanks to John Hawthorn <john@hawthorn.email> of GitHub

-- 
Aaron Patterson
http://tenderlovemaking.com/

["4-2-action-view-file-disclosure.patch" (text/plain)]

From 58ed245e80a8710fbe31e91417bfd19f9f934cc4 Mon Sep 17 00:00:00 2001
From: John Hawthorn <john@hawthorn.email>
Date: Mon, 4 Mar 2019 18:24:51 -0800
Subject: [PATCH] Only accept formats from registered mime types

[CVE-2019-5418]
[CVE-2019-5419]
---
 .../lib/action_dispatch/http/mime_negotiation.rb |  6 +++++-
 .../test/controller/mime/respond_to_test.rb      | 14 ++++++++------
 .../new_base/content_negotiation_test.rb         | 16 +++++++++++++---
 3 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb \
b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 53a98c5d0a..00fd3d03df 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -61,7 +61,7 @@ module ActionDispatch
                               false
                             end
 
-          if params_readable
+          v = if params_readable
             Array(Mime[parameters[:format]])
           elsif use_accept_header && valid_accept_header
             accepts
@@ -70,6 +70,10 @@ module ActionDispatch
           else
             [Mime::HTML]
           end
+
+          v.select do |format|
+            format.symbol || format.ref == "*/*"
+          end
         end
       end
 
diff --git a/actionpack/test/controller/mime/respond_to_test.rb \
b/actionpack/test/controller/mime/respond_to_test.rb index 66d2fd7716..07ad0085fc 100644
--- a/actionpack/test/controller/mime/respond_to_test.rb
+++ b/actionpack/test/controller/mime/respond_to_test.rb
@@ -87,9 +87,9 @@ class RespondToController < ActionController::Base
 
   def custom_type_handling
     respond_to do |type|
-      type.html { render :text => "HTML"    }
-      type.custom("application/crazy-xml")  { render :text => "Crazy XML"  }
-      type.all  { render :text => "Nothing" }
+      type.html { render text: "HTML"    }
+      type.custom("application/fancy-xml")  { render text: "Fancy XML"  }
+      type.all  { render text: "Nothing" }
     end
   end
 
@@ -269,12 +269,14 @@ class RespondToControllerTest < ActionController::TestCase
     @request.host = "www.example.com"
     Mime::Type.register_alias("text/html", :iphone)
     Mime::Type.register("text/x-mobile", :mobile)
+    Mime::Type.register("application/fancy-xml", :fancy_xml)
   end
 
   def teardown
     super
     Mime::Type.unregister(:iphone)
     Mime::Type.unregister(:mobile)
+    Mime::Type.unregister(:fancy_xml)
   end
 
   def test_html
@@ -430,10 +432,10 @@ class RespondToControllerTest < ActionController::TestCase
   end
 
   def test_custom_types
-    @request.accept = "application/crazy-xml"
+    @request.accept = "application/fancy-xml"
     get :custom_type_handling
-    assert_equal "application/crazy-xml", @response.content_type
-    assert_equal 'Crazy XML', @response.body
+    assert_equal "application/fancy-xml", @response.content_type
+    assert_equal "Fancy XML", @response.body
 
     @request.accept = "text/html"
     get :custom_type_handling
diff --git a/actionpack/test/controller/new_base/content_negotiation_test.rb \
b/actionpack/test/controller/new_base/content_negotiation_test.rb index 5fd5946619..57bf16ac9c \
                100644
--- a/actionpack/test/controller/new_base/content_negotiation_test.rb
+++ b/actionpack/test/controller/new_base/content_negotiation_test.rb
@@ -19,9 +19,19 @@ module ContentNegotiation
       assert_body "Hello world */*!"
     end
 
-    test "Not all mimes are converted to symbol" do
-      get "/content_negotiation/basic/all", {}, "HTTP_ACCEPT" => "text/plain, mime/another"
-      assert_body '[:text, "mime/another"]'
+    test "A js or */* Accept header will return HTML" do
+      get "/content_negotiation/basic/hello", {}, { "HTTP_ACCEPT" => "text/javascript, */*" }
+      assert_body "Hello world text/html!"
+    end
+
+    test "A js or */* Accept header on xhr will return HTML" do
+      xhr :get, "/content_negotiation/basic/hello", {}, { "HTTP_ACCEPT" => "text/javascript, \
*/*" } +      assert_body "Hello world text/javascript!"
+    end
+
+    test "Unregistered mimes are ignored" do
+      get "/content_negotiation/basic/all", {}, { "HTTP_ACCEPT" => "text/plain, mime/another" \
} +      assert_body '[:text]'
     end
   end
 end
-- 
2.21.0


["5-0-action-view-file-disclosure.patch" (text/plain)]

From c79dcbce9bfd20fe7f72ca431c49965ee39bd645 Mon Sep 17 00:00:00 2001
From: John Hawthorn <john@hawthorn.email>
Date: Mon, 4 Mar 2019 18:24:51 -0800
Subject: [PATCH] Only accept formats from registered mime types

[CVE-2019-5418]
[CVE-2019-5419]
---
 .../lib/action_dispatch/http/mime_negotiation.rb   |  5 +++++
 actionpack/test/controller/mime/respond_to_test.rb | 10 ++++++----
 .../new_base/content_negotiation_test.rb           | 14 ++++++++++++--
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb \
b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index f17b93fad7..a39052e6f7 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -76,6 +76,11 @@ def formats
           else
             [Mime[:html]]
           end
+
+          v = v.select do |format|
+            format.symbol || format.ref == "*/*"
+          end
+
           set_header k, v
         end
       end
diff --git a/actionpack/test/controller/mime/respond_to_test.rb \
b/actionpack/test/controller/mime/respond_to_test.rb index 993f4001de..d113db8b76 100644
--- a/actionpack/test/controller/mime/respond_to_test.rb
+++ b/actionpack/test/controller/mime/respond_to_test.rb
@@ -104,7 +104,7 @@ def made_for_content_type
   def custom_type_handling
     respond_to do |type|
       type.html { render body: "HTML"    }
-      type.custom("application/crazy-xml")  { render body: "Crazy XML"  }
+      type.custom("application/fancy-xml")  { render body: "Fancy XML"  }
       type.all  { render body: "Nothing" }
     end
   end
@@ -294,12 +294,14 @@ def setup
     @request.host = "www.example.com"
     Mime::Type.register_alias("text/html", :iphone)
     Mime::Type.register("text/x-mobile", :mobile)
+    Mime::Type.register("application/fancy-xml", :fancy_xml)
   end
 
   def teardown
     super
     Mime::Type.unregister(:iphone)
     Mime::Type.unregister(:mobile)
+    Mime::Type.unregister(:fancy_xml)
   end
 
   def test_html
@@ -455,10 +457,10 @@ def test_synonyms
   end
 
   def test_custom_types
-    @request.accept = "application/crazy-xml"
+    @request.accept = "application/fancy-xml"
     get :custom_type_handling
-    assert_equal "application/crazy-xml", @response.content_type
-    assert_equal 'Crazy XML', @response.body
+    assert_equal "application/fancy-xml", @response.content_type
+    assert_equal "Fancy XML", @response.body
 
     @request.accept = "text/html"
     get :custom_type_handling
diff --git a/actionpack/test/controller/new_base/content_negotiation_test.rb \
b/actionpack/test/controller/new_base/content_negotiation_test.rb index c0e92b3b05..b867bcd675 \
                100644
--- a/actionpack/test/controller/new_base/content_negotiation_test.rb
+++ b/actionpack/test/controller/new_base/content_negotiation_test.rb
@@ -19,9 +19,19 @@ def all
       assert_body "Hello world */*!"
     end
 
-    test "Not all mimes are converted to symbol" do
+    test "A js or */* Accept header will return HTML" do
+      get "/content_negotiation/basic/hello", headers: { "HTTP_ACCEPT" => "text/javascript, \
*/*" } +      assert_body "Hello world text/html!"
+    end
+
+    test "A js or */* Accept header on xhr will return HTML" do
+      get "/content_negotiation/basic/hello", headers: { "HTTP_ACCEPT" => "text/javascript, \
*/*" }, xhr: true +      assert_body "Hello world text/javascript!"
+    end
+
+    test "Unregistered mimes are ignored" do
       get "/content_negotiation/basic/all", headers: { "HTTP_ACCEPT" => "text/plain, \
                mime/another" }
-      assert_body '[:text, "mime/another"]'
+      assert_body '[:text]'
     end
   end
 end
-- 
2.21.0


["5-1-action-view-file-disclosure.patch" (text/plain)]

From 92c025d7f17ff256ac50f5e3bc014bb1a016d1ec Mon Sep 17 00:00:00 2001
From: John Hawthorn <john@hawthorn.email>
Date: Mon, 4 Mar 2019 18:24:51 -0800
Subject: [PATCH] Only accept formats from registered mime types

[CVE-2019-5418]
[CVE-2019-5419]
---
 .../lib/action_dispatch/http/mime_negotiation.rb   |  5 +++++
 actionpack/test/controller/mime/respond_to_test.rb | 10 ++++++----
 .../new_base/content_negotiation_test.rb           | 14 ++++++++++++--
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb \
b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index c4fe3a5c09..9a93a454bc 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -76,6 +76,11 @@ def formats
           else
             [Mime[:html]]
           end
+
+          v = v.select do |format|
+            format.symbol || format.ref == "*/*"
+          end
+
           set_header k, v
         end
       end
diff --git a/actionpack/test/controller/mime/respond_to_test.rb \
b/actionpack/test/controller/mime/respond_to_test.rb index 61bd5c80c4..0ab3b696c5 100644
--- a/actionpack/test/controller/mime/respond_to_test.rb
+++ b/actionpack/test/controller/mime/respond_to_test.rb
@@ -103,7 +103,7 @@ def made_for_content_type
   def custom_type_handling
     respond_to do |type|
       type.html { render body: "HTML"    }
-      type.custom("application/crazy-xml")  { render body: "Crazy XML"  }
+      type.custom("application/fancy-xml")  { render body: "Fancy XML"  }
       type.all  { render body: "Nothing" }
     end
   end
@@ -292,12 +292,14 @@ def setup
     @request.host = "www.example.com"
     Mime::Type.register_alias("text/html", :iphone)
     Mime::Type.register("text/x-mobile", :mobile)
+    Mime::Type.register("application/fancy-xml", :fancy_xml)
   end
 
   def teardown
     super
     Mime::Type.unregister(:iphone)
     Mime::Type.unregister(:mobile)
+    Mime::Type.unregister(:fancy_xml)
   end
 
   def test_html
@@ -453,10 +455,10 @@ def test_synonyms
   end
 
   def test_custom_types
-    @request.accept = "application/crazy-xml"
+    @request.accept = "application/fancy-xml"
     get :custom_type_handling
-    assert_equal "application/crazy-xml", @response.content_type
-    assert_equal "Crazy XML", @response.body
+    assert_equal "application/fancy-xml", @response.content_type
+    assert_equal "Fancy XML", @response.body
 
     @request.accept = "text/html"
     get :custom_type_handling
diff --git a/actionpack/test/controller/new_base/content_negotiation_test.rb \
b/actionpack/test/controller/new_base/content_negotiation_test.rb index b870745031..edf3545782 \
                100644
--- a/actionpack/test/controller/new_base/content_negotiation_test.rb
+++ b/actionpack/test/controller/new_base/content_negotiation_test.rb
@@ -18,9 +18,19 @@ def all
       assert_body "Hello world */*!"
     end
 
-    test "Not all mimes are converted to symbol" do
+    test "A js or */* Accept header will return HTML" do
+      get "/content_negotiation/basic/hello", headers: { "HTTP_ACCEPT" => "text/javascript, \
*/*" } +      assert_body "Hello world text/html!"
+    end
+
+    test "A js or */* Accept header on xhr will return HTML" do
+      get "/content_negotiation/basic/hello", headers: { "HTTP_ACCEPT" => "text/javascript, \
*/*" }, xhr: true +      assert_body "Hello world text/javascript!"
+    end
+
+    test "Unregistered mimes are ignored" do
       get "/content_negotiation/basic/all", headers: { "HTTP_ACCEPT" => "text/plain, \
                mime/another" }
-      assert_body '[:text, "mime/another"]'
+      assert_body '[:text]'
     end
   end
 end
-- 
2.21.0


["5-2-action-view-file-disclosure.patch" (text/plain)]

From d7fac9c09a535ec7f11bb9aa8addb4af37b7d4b5 Mon Sep 17 00:00:00 2001
From: John Hawthorn <john@hawthorn.email>
Date: Mon, 4 Mar 2019 18:24:51 -0800
Subject: [PATCH] Only accept formats from registered mime types

[CVE-2019-5418]
[CVE-2019-5419]
---
 .../lib/action_dispatch/http/mime_negotiation.rb   |  5 +++++
 actionpack/test/controller/mime/respond_to_test.rb | 10 ++++++----
 .../new_base/content_negotiation_test.rb           | 14 ++++++++++++--
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb \
b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index d7435fa8df..ada52adfeb 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -74,6 +74,11 @@ def formats
           else
             [Mime[:html]]
           end
+
+          v = v.select do |format|
+            format.symbol || format.ref == "*/*"
+          end
+
           set_header k, v
         end
       end
diff --git a/actionpack/test/controller/mime/respond_to_test.rb \
b/actionpack/test/controller/mime/respond_to_test.rb index f9ffd5f54c..a80cef83b7 100644
--- a/actionpack/test/controller/mime/respond_to_test.rb
+++ b/actionpack/test/controller/mime/respond_to_test.rb
@@ -105,7 +105,7 @@ def made_for_content_type
   def custom_type_handling
     respond_to do |type|
       type.html { render body: "HTML"    }
-      type.custom("application/crazy-xml")  { render body: "Crazy XML"  }
+      type.custom("application/fancy-xml")  { render body: "Fancy XML"  }
       type.all  { render body: "Nothing" }
     end
   end
@@ -294,12 +294,14 @@ def setup
     @request.host = "www.example.com"
     Mime::Type.register_alias("text/html", :iphone)
     Mime::Type.register("text/x-mobile", :mobile)
+    Mime::Type.register("application/fancy-xml", :fancy_xml)
   end
 
   def teardown
     super
     Mime::Type.unregister(:iphone)
     Mime::Type.unregister(:mobile)
+    Mime::Type.unregister(:fancy_xml)
   end
 
   def test_html
@@ -455,10 +457,10 @@ def test_synonyms
   end
 
   def test_custom_types
-    @request.accept = "application/crazy-xml"
+    @request.accept = "application/fancy-xml"
     get :custom_type_handling
-    assert_equal "application/crazy-xml", @response.content_type
-    assert_equal "Crazy XML", @response.body
+    assert_equal "application/fancy-xml", @response.content_type
+    assert_equal "Fancy XML", @response.body
 
     @request.accept = "text/html"
     get :custom_type_handling
diff --git a/actionpack/test/controller/new_base/content_negotiation_test.rb \
b/actionpack/test/controller/new_base/content_negotiation_test.rb index 7205e90176..6de91c57b7 \
                100644
--- a/actionpack/test/controller/new_base/content_negotiation_test.rb
+++ b/actionpack/test/controller/new_base/content_negotiation_test.rb
@@ -20,9 +20,19 @@ def all
       assert_body "Hello world */*!"
     end
 
-    test "Not all mimes are converted to symbol" do
+    test "A js or */* Accept header will return HTML" do
+      get "/content_negotiation/basic/hello", headers: { "HTTP_ACCEPT" => "text/javascript, \
*/*" } +      assert_body "Hello world text/html!"
+    end
+
+    test "A js or */* Accept header on xhr will return HTML" do
+      get "/content_negotiation/basic/hello", headers: { "HTTP_ACCEPT" => "text/javascript, \
*/*" }, xhr: true +      assert_body "Hello world text/javascript!"
+    end
+
+    test "Unregistered mimes are ignored" do
       get "/content_negotiation/basic/all", headers: { "HTTP_ACCEPT" => "text/plain, \
                mime/another" }
-      assert_body '[:text, "mime/another"]'
+      assert_body '[:text]'
     end
   end
 end
-- 
2.21.0


["6-0-action-view-file-disclosure.patch" (text/plain)]

From f4c70c2222180b8d9d924f00af0c7fd632e26715 Mon Sep 17 00:00:00 2001
From: John Hawthorn <john@hawthorn.email>
Date: Mon, 4 Mar 2019 18:24:51 -0800
Subject: [PATCH] Only accept formats from registered mime types

[CVE-2019-5418]
[CVE-2019-5419]
---
 .../lib/action_dispatch/http/mime_negotiation.rb   |  5 +++++
 actionpack/test/controller/mime/respond_to_test.rb | 10 ++++++----
 .../new_base/content_negotiation_test.rb           | 14 ++++++++++++--
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb \
b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 498b1e6695..4e81ba12a5 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -79,6 +79,11 @@ def formats
           else
             [Mime[:html]]
           end
+
+          v = v.select do |format|
+            format.symbol || format.ref == "*/*"
+          end
+
           set_header k, v
         end
       end
diff --git a/actionpack/test/controller/mime/respond_to_test.rb \
b/actionpack/test/controller/mime/respond_to_test.rb index 00e1d5f3b3..21de05b323 100644
--- a/actionpack/test/controller/mime/respond_to_test.rb
+++ b/actionpack/test/controller/mime/respond_to_test.rb
@@ -125,7 +125,7 @@ def using_non_conflicting_nested_js_then_js
   def custom_type_handling
     respond_to do |type|
       type.html { render body: "HTML"    }
-      type.custom("application/crazy-xml")  { render body: "Crazy XML"  }
+      type.custom("application/fancy-xml")  { render body: "Fancy XML"  }
       type.all  { render body: "Nothing" }
     end
   end
@@ -314,12 +314,14 @@ def setup
     @request.host = "www.example.com"
     Mime::Type.register_alias("text/html", :iphone)
     Mime::Type.register("text/x-mobile", :mobile)
+    Mime::Type.register("application/fancy-xml", :fancy_xml)
   end
 
   def teardown
     super
     Mime::Type.unregister(:iphone)
     Mime::Type.unregister(:mobile)
+    Mime::Type.unregister(:fancy_xml)
   end
 
   def test_html
@@ -489,10 +491,10 @@ def test_synonyms
   end
 
   def test_custom_types
-    @request.accept = "application/crazy-xml"
+    @request.accept = "application/fancy-xml"
     get :custom_type_handling
-    assert_equal "application/crazy-xml", @response.content_type
-    assert_equal "Crazy XML", @response.body
+    assert_equal "application/fancy-xml", @response.content_type
+    assert_equal "Fancy XML", @response.body
 
     @request.accept = "text/html"
     get :custom_type_handling
diff --git a/actionpack/test/controller/new_base/content_negotiation_test.rb \
b/actionpack/test/controller/new_base/content_negotiation_test.rb index 7205e90176..6de91c57b7 \
                100644
--- a/actionpack/test/controller/new_base/content_negotiation_test.rb
+++ b/actionpack/test/controller/new_base/content_negotiation_test.rb
@@ -20,9 +20,19 @@ def all
       assert_body "Hello world */*!"
     end
 
-    test "Not all mimes are converted to symbol" do
+    test "A js or */* Accept header will return HTML" do
+      get "/content_negotiation/basic/hello", headers: { "HTTP_ACCEPT" => "text/javascript, \
*/*" } +      assert_body "Hello world text/html!"
+    end
+
+    test "A js or */* Accept header on xhr will return HTML" do
+      get "/content_negotiation/basic/hello", headers: { "HTTP_ACCEPT" => "text/javascript, \
*/*" }, xhr: true +      assert_body "Hello world text/javascript!"
+    end
+
+    test "Unregistered mimes are ignored" do
       get "/content_negotiation/basic/all", headers: { "HTTP_ACCEPT" => "text/plain, \
                mime/another" }
-      assert_body '[:text, "mime/another"]'
+      assert_body '[:text]'
     end
   end
 end
-- 
2.21.0


["signature.asc" (application/pgp-signature)]

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic