docker搭建漏洞復(fù)現(xiàn)環(huán)境
漏洞原理看幫助文檔
# Django debug page XSS漏洞(CVE-2017-12794)分析
Django發(fā)布了新版本1.11.5,修復(fù)了500頁(yè)面中可能存在的一個(gè)XSS漏洞,這篇文章說(shuō)明一下該漏洞的原理和復(fù)現(xiàn),和我的一點(diǎn)點(diǎn)評(píng)。
## 0x01 補(bǔ)丁分析
因?yàn)楣俜秸f(shuō)明是500頁(yè)面中出現(xiàn)的BUG,所以我們重點(diǎn)關(guān)注的就是`django/views/debug.py`。
Github上有Django的倉(cāng)庫(kù),下載下來(lái),用1.11.4和1.11.5進(jìn)行比較:
```bash
git clone https://github.com/django/django.git
cd django
git diff 1.11.4 1.11.5 django/views/debug.py
```

可見(jiàn),外部關(guān)閉了全局轉(zhuǎn)義,然后在這兩個(gè)地方增加了強(qiáng)制轉(zhuǎn)義。那么,漏洞肯定是在這個(gè)位置觸發(fā)的。
## 0x02 功能點(diǎn)探索
如果要觸發(fā)這兩個(gè)輸出點(diǎn),就必須進(jìn)入這個(gè)if語(yǔ)句:`{% ifchanged frame.exc_cause %}{% if frame.exc_cause %}`。
首先我們來(lái)想一下,正常情況下,這個(gè)位置是干嘛用的,也就是說(shuō),功能點(diǎn)是什么。
作為一個(gè)老年Django開發(fā),看到上圖畫框的這個(gè)關(guān)鍵句子`The above exception was the direct cause of the following exception:`,我是有印象的:一般是在出現(xiàn)數(shù)據(jù)庫(kù)異常的時(shí)候,會(huì)拋出這樣的錯(cuò)誤語(yǔ)句。
我們可以做個(gè)簡(jiǎn)單的測(cè)試,在Django命令行下,我們創(chuàng)建一個(gè)username為phith0n的用戶,然后再次創(chuàng)建一個(gè)username為phith0n的用戶,則會(huì)拋出一個(gè)`IntegrityError`異常:

見(jiàn)上圖,原因是觸發(fā)了數(shù)據(jù)庫(kù)的Unique異常。
為什么Django會(huì)引入這樣一個(gè)異常機(jī)制?這是為了方便開發(fā)者進(jìn)行SQL錯(cuò)誤的調(diào)試,因?yàn)镈jango的模型最終是操作數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)中具體出現(xiàn)什么錯(cuò)誤,是Django無(wú)法100%預(yù)測(cè)的。那么,為了方便開發(fā)者快速找到是哪個(gè)操作觸發(fā)了數(shù)據(jù)庫(kù)異常,就需要將這兩個(gè)異?;厮輻jP(guān)聯(lián)到一塊。
我們可以看看代碼,`django/db/utils.py`的`__exit__`函數(shù):
```python
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`之一,則拋出一個(gè)同類型的新異常,并設(shè)置其`__cause__`和`__traceback__`為此時(shí)上下文的`exc_value`和`traceback`。
`exc_value`是上一個(gè)異常的說(shuō)明,`traceback`是上一個(gè)異常的回溯棧。這個(gè)函數(shù)其實(shí)就是關(guān)聯(lián)了上一個(gè)異常和當(dāng)前的新異常。
最后,在500頁(yè)面中,`__cause__`被輸出。
## 0x03 漏洞復(fù)現(xiàn)
經(jīng)過(guò)我的測(cè)試,我發(fā)現(xiàn)在使用Postgres數(shù)據(jù)庫(kù)并觸發(fā)異常的時(shí)候,psycopg2會(huì)將字段名和字段值全部拋出。那么,如果字段值中包含我們可控的字符串,又由于0x02中說(shuō)到的,這個(gè)字符串其實(shí)就會(huì)被設(shè)置成`__cause__`,最后被顯示在頁(yè)面中。
所以我們假設(shè)有如下場(chǎng)景:
1. 用戶注冊(cè)頁(yè)面,未檢查用戶名
2. 注冊(cè)一個(gè)用戶名為`<script>alert(1)</script>`的用戶
3. 再次注冊(cè)一個(gè)用戶名為`<script>alert(1)</script>`的用戶
4. 觸發(fā)duplicate key異常,導(dǎo)致XSS漏洞
我將上述流程整理成vulhub的一個(gè)環(huán)境:https://github.com/phith0n/vulhub/tree/master/django/C
http://your-ip:8000/create_user/?username=<script>alert(1)</script>`創(chuàng)建一個(gè)用戶,成功;再次訪問(wèn)`http://your-ip:8000/create_user/?username=<script>alert(1)</script>`,觸發(fā)異常:
因?yàn)楸籯ali的瀏覽器攔截了,用本機(jī)的瀏覽器實(shí)驗(yàn)
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-688093.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-688093.html
到了這里,關(guān)于django/CVE-2017-12794XSS漏洞復(fù)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!