Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.6.x] Prevented arbitrary file inclusion with {% ssi %} tag and rel…

…ative paths.

Thanks Rainer Koirikivi for the report and draft patch.

This is a security fix; disclosure to follow shortly.

Backport of 7fe5b65 from master
  • Loading branch information...
commit 536cc64240f7f331b805104bfd8cd82c98e44f12 1 parent ef3604a
Tim Graham authored August 27, 2013
2  django/template/defaulttags.py
... ...
@@ -1,6 +1,7 @@
1 1
 """Default tags used by the template system, available to all templates."""
2 2
 from __future__ import unicode_literals
3 3
 
  4
+import os
4 5
 import sys
5 6
 import re
6 7
 from datetime import datetime
@@ -332,6 +333,7 @@ def render(self, context):
332 333
         return ''
333 334
 
334 335
 def include_is_allowed(filepath):
  336
+    filepath = os.path.abspath(filepath)
335 337
     for root in settings.ALLOWED_INCLUDE_ROOTS:
336 338
         if filepath.startswith(root):
337 339
             return True
31  tests/template_tests/tests.py
@@ -1832,3 +1832,34 @@ def test_include_only(self):
1832 1832
             template.Template('{% include "child" only %}').render(ctx),
1833 1833
             'none'
1834 1834
         )
  1835
+
  1836
+
  1837
+class SSITests(TestCase):
  1838
+    def setUp(self):
  1839
+        self.this_dir = os.path.dirname(os.path.abspath(upath(__file__)))
  1840
+        self.ssi_dir = os.path.join(self.this_dir, "templates", "first")
  1841
+
  1842
+    def render_ssi(self, path):
  1843
+        # the path must exist for the test to be reliable
  1844
+        self.assertTrue(os.path.exists(path))
  1845
+        return template.Template('{%% ssi "%s" %%}' % path).render(Context())
  1846
+
  1847
+    def test_allowed_paths(self):
  1848
+        acceptable_path = os.path.join(self.ssi_dir, "..", "first", "test.html")
  1849
+        with override_settings(ALLOWED_INCLUDE_ROOTS=(self.ssi_dir,)):
  1850
+            self.assertEqual(self.render_ssi(acceptable_path), 'First template\n')
  1851
+
  1852
+    def test_relative_include_exploit(self):
  1853
+        """
  1854
+        May not bypass ALLOWED_INCLUDE_ROOTS with relative paths
  1855
+
  1856
+        e.g. if ALLOWED_INCLUDE_ROOTS = ("/var/www",), it should not be
  1857
+        possible to do {% ssi "/var/www/../../etc/passwd" %}
  1858
+        """
  1859
+        disallowed_paths = [
  1860
+            os.path.join(self.ssi_dir, "..", "ssi_include.html"),
  1861
+            os.path.join(self.ssi_dir, "..", "second", "test.html"),
  1862
+        ]
  1863
+        with override_settings(ALLOWED_INCLUDE_ROOTS=(self.ssi_dir,)):
  1864
+            for path in disallowed_paths:
  1865
+                self.assertEqual(self.render_ssi(path), '')

0 notes on commit 536cc64

Please sign in to comment.
Something went wrong with that request. Please try again.