<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

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

    Path django/CVE-2017-12794
    Django發布了新版本1.11.5,修復了500頁面中可能存在的一個XSS漏洞,這篇文章說明一下該漏洞的原理和復現,和我的一點點評。

    0x01 補丁分析

    因為官方說明是500頁面中出現的BUG,所以我們重點關注的就是django/views/debug.py

    Github上有Django的倉庫,下載下來,用1.11.4和1.11.5進行比較:

    git clone https://github.com/django/django.git
    cd django
    git diff 1.11.4 1.11.5 django/views/debug.py

    sp170908_035017

    可見,外部關閉了全局轉義,然后在這兩個地方增加了強制轉義。那么,漏洞肯定是在這個位置觸發的。

    0x02 功能點探索

    如果要觸發這兩個輸出點,就必須進入這個if語句:{% ifchanged frame.exc_cause %}{% if frame.exc_cause %}

    首先我們來想一下,正常情況下,這個位置是干嘛用的,也就是說,功能點是什么。

    作為一個老年Django開發,看到上圖畫框的這個關鍵句子The above exception was the direct cause of the following exception:,我是有印象的:一般是在出現數據庫異常的時候,會拋出這樣的錯誤語句。

    我們可以做個簡單的測試,在Django命令行下,我們創建一個username為phith0n的用戶,然后再次創建一個username為phith0n的用戶,則會拋出一個IntegrityError異常:

    sp170908_040738

    見上圖,原因是觸發了數據庫的Unique異常。

    為什么Django會引入這樣一個異常機制?這是為了方便開發者進行SQL錯誤的調試,因為Django的模型最終是操作數據庫,數據庫中具體出現什么錯誤,是Django無法100%預測的。那么,為了方便開發者快速找到是哪個操作觸發了數據庫異常,就需要將這兩個異常回溯棧關聯到一塊。

    我們可以看看代碼,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,OperationalError,IntegrityError,InternalError,ProgrammingError,NotSupportedError,DatabaseError,InterfaceError,Error之一,則拋出一個同類型的新異常,并設置其__cause____traceback__為此時上下文的exc_valuetraceback

    exc_value是上一個異常的說明,traceback是上一個異常的回溯棧。這個函數其實就是關聯了上一個異常和當前的新異常。

    最后,在500頁面中,__cause__被輸出。

    0x03 漏洞復現

    經過我的測試,我發現在使用Postgres數據庫并觸發異常的時候,psycopg2會將字段名和字段值全部拋出。那么,如果字段值中包含我們可控的字符串,又由于0x02中說到的,這個字符串其實就會被設置成__cause__,最后被顯示在頁面中。

    所以我們假設有如下場景:

    1. 用戶注冊頁面,未檢查用戶名
    2. 注冊一個用戶名為<script>alert(1)</script>的用戶
    3. 再次注冊一個用戶名為<script>alert(1)</script>的用戶
    4. 觸發duplicate key異常,導致XSS漏洞

    我將上述流程整理成vulhub的一個環境:https://github.com/phith0n/vulhub/tree/master/django/CVE-2017-12794

    編譯及啟動環境:

    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>,觸發異常:

    sp170908_055317

    可見,Postgres拋出的異常為

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

    這個異常被拼接進The above exception ({{ frame.exc_cause }}) was the direct cause of the following exception,最后觸發XSS。

    本文章首發在 網安wangan.com 網站上。

    上一篇 下一篇
    討論數量: 0
    只看當前版本


    暫無話題~
    亚洲 欧美 自拍 唯美 另类