Django浅显分析
之前遇到过一些关于Django的题,总是很混沌,感觉不知道该怎么做,没有仔细的学习一下,今天看了p神的两篇文章和Boogipop
大佬关于Django
的博客,感觉关于Django
的认知要清晰一点了,记录一下自己今天所学习到的知识。
Django项目组成
大佬博客指路:Django - Boogiepop Doesn’t Laugh (boogipop.com),里面详细解释了如何创建一个Django
项目,并且解释了相关文件的作用。我认为比较重要的有:
- 默认项目文件中的
urls.py
:里面有关于项目的路由设置,包含了url
路径和视图函数对应关系 - 默认项目文件中的
manage.py
:该文件负责项目的管理,启动,创建app
,数据库管理等等都,十分重要 - 默认项目文件中的
settings.py
:关于项目的配置信息,一般来说无法获得,如果泄露,极易泄露敏感信息
通过manage.py
创建app
后,app
里会生成几个文件,比较重要的有:
views.py
:对应于默认项目文件中的urls.py
,urls.py
添加路径的时候会添加对应的路径处理函数,这些函数就位于views.py
中models.py
:对数据库的相关内容进行操作
除了上述这些文件,Django
项目中还有其他目录,例如template
目录存放模板(.html
)文件,static
目录下存放静态(css,js
,图片等)文件
Django语法
{{}}
:引用变量{%%}
:写入语句,判断与循环语句
Django漏洞分析
格式化字符串漏洞
p神博客:Python 格式化字符串漏洞(Django为例) | 离别歌 (leavesongs.com)
例:
def view(request, *args, **kwargs):
template = 'Hello {user}, This is your email: ' + request.GET.get('email')
return HttpResponse(template.format(user=request.user))
- 格式化字符串可控,虽然无法进行任意命令执行,但是我们可以通过“获取对象属性”、“获取数组数值”等方法来获取敏感信息。
- 例如
format
参数中传入了变量user=request.user
(Django
中request.user
就是当前用户对象),那我们就可以通过引用变量的属性值,来进行信息泄露,例如传入email={user.password}
,就可以泄露用户密码。 - 但是只得到这点信息是不够的,更重要的是去得到
setting.py
中的信息,这就需要挖掘Django
自带的应用中的一些路径,最终读取到Django
的配置项。 - p神的博客中指出,
Django
自带的应用admin
(也就是Django
自带的后台)的models.py
中导入了当前网站的配置文件setting.py
。因此只需要通过某种方式,找到Django
默认应用admin
的model
,再通过这个model
获取settings
对象,进而获取数据库账号密码、Web
加密密钥等信息。 - p神给出了两种方式:
{user.groups.model._meta.app_config.module.admin.settings.SECRET_KEY}
{user.user_permissions.model._meta.app_config.module.admin.settings.SECRET_KEY}
- 以及看见了其他人的调用方式:
{user.__class__._meta.app_config.module.admin.settings.SECRET_KEY}
模版注入漏洞
例:
@login_required
def index(request):
django_engine = engines['django']
template = django_engine.from_string('My name is ' + request.user.username)
return HttpResponse(template.render(None, request))
- 对于
request.user.username
,我们是可控的,而且存在template.render
,所以这里存在ssti
漏洞。 - 对于
Django
来说,模版注入漏洞进行任意命令执行是比较困难的,更多的是通过模版注入来拿到敏感信息。这里有点类似于上面的格式化字符串漏洞了,但是Django
的模板引擎有一定限制,无法读取用下划线开头的属性。所以格式化字符串漏洞的payload
无法使用。 - 在
Django
项目中,存在很多变量,一般来说request
、user
、和perms
都是默认存在的,我们可以通过挖掘变量之间的关系来读取敏感信息,具体参考p神博客:Code-Breaking中的两个Python沙箱 | 离别歌 (leavesongs.com)。
反序列化漏洞
在Django
的配置文件中关于session
的默认配置为:
SESSION_ENGINE=django.contrib.sessions.backends.db
:session
存储在数据库中SESSION_SERIALIZER=django.contrib.sessions.serializers.JSONSerializer
:session
使用json
形式
但是在一些题目中,将这两个设置更改为了:
SESSION_ENGINE=django.contrib.sessions.backends.signed_cookies
:cookie
经过signed
后存储SESSION_SERIALIZER=django.contrib.sessions.serializers.PickleSerialzer
:使用pickle
作为session
的序列化方式(例题:[DASCTF 2023 & 0X401七月暑期挑战赛]ez_py);或者:SESSION_SERIALIZER = core.serializer.PickleSerializer
(例题:Code-Breaking-2018,考察反序列化沙盒绕过)
这两个例子中都选择了pickel
作为session
反序列化的方式,而如果我们可控pickle.loads()
的参数,我们就可以进行python pickle
反序列化漏洞的攻击。
现在感觉自己对pickle
反序列化还没有自己的理解和认知,以后再写一篇关于pickle
反序列化的文章。