Django开发与攻防测试(入门篇)

x
用微信扫描二维码
分享至好友和朋友圈

  最近在培训包括在一些比赛中,python框架方面的攻防需求出现的越来越频繁。

  虽然python框架相对于Java、php等的广泛度还略低一点(当然现在的流行程度已经越来越高了),但是我们并不能够因此而忽视其的安全性。比如在一些赛事中就常用flask来出题等等,所以花时间学习python框架的开发与攻防对于web选手来说还是一件比较重要的事情,所以撰写这篇文章,希望可以给一些想要快速入门的同学一点帮助,同时也能共同进步。

  如有错误的地方,还请各位师兄与同学斧正。

  

  依稀记得以前用django + semantic ui + mongodb搭博客还是大学一年级的时候,时光匆匆啊….

  

一、Django基础开发

  以前搭博客用的是1.8.2,还在机子上装着没卸,顺便拿过来用,当然新版本会修复很多bug,尽可能还是要去学习新一些的版本,此篇权当入门篇。

  1、下载安装与启动 # 下载django pip install django==1.8.2 -i https://pypi.mirrors.ustc.edu.cn/simple/ # 创建文件夹并启动虚拟环境 virtualenv django_demo cd django_demo source bin/activate # 创建存放django文件的文件夹 mkdir learn_django cd learn_django # 创建项目 python django-admin.py startproject django_web # 创建应用 python manage.py startapp django_app # 编辑django_web中的settings.py文件,将django_app加入到apps中

  
这样就完成了最基础的搭建

  
这样就完成了最基础的搭建

  

  

  运行服务看一下

  
2、Django框架中的MVC与MTV 2、Django框架中的MVC与MTV

  MVC是众所周知的模式:model(模型)、view(视图)、controller(控制器)

  用户在页面输入url,转交给url控制器,然后根据url匹配相应的视图函数,viwe会去到models取数据,然后models在数据库中取得数据后返回给视图,视图把要展示的数据返回给模版,然后就输出到页面上。

  
Django也是一个MVC框架,但是在Django中,控制器接受用户输入的部分由框架自行处理,所以django更加关注的是 模型(model)、view(视图)、templates(模版),也就是MTV模型。

  
Django也是一个MVC框架,但是在Django中,控制器接受用户输入的部分由框架自行处理,所以django更加关注的是 模型(model)、view(视图)、templates(模版),也就是MTV模型。

  请求一个url后,匹配相应的view区,view去models(一个托管数据的层级)查找我们要的数据,然后将数据装载到templates层,然后呈献给我们。
两者很像,可以说MTV基于MVC。

  
两者很像, 可以说MTV基于MVC。 3、静态Web开发

  创建模版层

  当然,要是只想让简单的数据显示在Web页面中,不需要创建模版,直接在views函数中相应回去就可以了,但是还是正规化一点。

  在learn_django中创建templates文件夹(如果是IDE创建的django项目会自动创建),这就是我们的模版文件夹,来添加一个可视化的模版index.html

  <!DOCTYPE html> <html> <head> <title>Django Learning</title> </head> <body> <h1>Hellow,Django!</h1>> </body> </html>

  创建视图层

  视图层通常来说是一个视图函数,与url进行匹配返回传入对应的Web页面

  from django.shortcuts import render # Create your views here. def index(request): return render(request,'index.html')

  创建url层

  创建url层,根据传入的url来找到我们的视图函数,从而将渲染的模版返回

  from django.conf.urls import include, url from django.contrib import admin from django_app.views import index urlpatterns = [ url(r'^admin/', include(admin.site.urls)), # 用正则去对url进行匹配,然后将视图函数匹配给相应的url url(r'^index/',index),

  运行服务,默认在8000端口

  python manage.py runserver

  

  


  到这一步有一部分同学会有一些小问题,那就是并不能返回模版,可能Windows和linux情况各不相同,linux需要把templates目录放在app目录下才可以找到。

  原因就在于settings.py中模版路径设置问题,如果templates目录是放在项目根目录,在settings中将templates路径加入就可以了。

  

  

  

  

  
4、动态web开发

  前边是说静态页面,如果需要实现动态,那就不得不说与数据库存储的交互问题,需要对models进行对应的编写来取得数据。

  mysql + django

  安装对应的数据库接口驱动,这里大致有三种:mysqldb、pymysql、mysqlclient。

  默认使用web根目录下的sqlite3数据库

  
将其修改为相应的mysql信息

  
将其修改为相应的mysql信息

  
创建mysql数据库,指定字符集为UTF-8

  
创建mysql数据库,指定字符集为UTF-8

  
models层

  
models层

  
创建模型的对象和数据库字段的对应关系

  
创建模型的对象和数据库字段的对应关系

  
字段定义中的特殊属性

  
字段定义中的特殊属性

  

  
from django.db import models # Create your models here. class DjangoTest(models.Model): text = models.CharField(max_length=20) 生成迁移文件并执行迁移 python manage.py makemigrations python manage.py migrate

  

  

  查看创建的信息

  

  建立一些测试数据

  

  在去创建views层之前,我们先对models层进行测试,看是否提取出了数据

  可以用两种方法:

  1、直接在models中填写提取数据

  也可以写在view层,这个无所谓

  
运行后可能会出现,因为在项目中单独运行python文件,需要搜索环境变量,而并没有指定,所以需要进行设置

  
运行后可能会出现,因为在项目中单独运行python文件,需要搜索环境变量,而并没有指定,所以需要进行设置


  django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS.....

  

  pycharm解决方法:https://blog.csdn.net/u011013781/article/details/52155761

  2、使用django shell

  # 打开django shell python manage.py shell import django django.setup() from django_app.models imoort DjangoTest as dj # 添加数据,结果见下方图片 a = dj(text="django shell test") a.save() # 查询数据,get查询单个数据,filter查询多个模型,all查询 dj.objects.all()

  

  

  django admin可以帮我们快速管理后台数据

  # 创建管理员 python manage.py createsuperuser ``` ![](http://oxrfjovwk.bkt.clouddn.com/18-6-29/76119583.jpg)

  将我们的模型注册到admin中,打开admin.py

  

  

  将我们的模型注册到admin中,打开admin.py

  from django.contrib import admin # Register your models here. from models import DjangoTest admin.site.register(DjangoTest)

  这样就可以在管理员界面管理模型

  
view与url层

  
view与url层

  当用户请求django站点上的某个页面时,django会使用路由解析模块来解析路由,默认是app目录下的urls.py。

  django加载该路由解析模块,并寻找可用的urlpatterns,这是一个python列表,然后django依次匹配列表中每个url模式,在遇到第一个与请求相匹配的模式时停下来,然后调用对应的视图,视图是一个python函数(或者是一个基于类的视图)。

  一个简单的路由选择模块示例:

  from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/([0-9]{4})/$', views.year_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ]

  与之对应的请求的例子:

  

  对/articles/2005/03/ 的请求将匹配列表中的第三个模式。Django 将调用函数views.month_archive(request, ’2005′, ’03′)。

  /articles/2005/3/ 不匹配任何URL 模式,因为列表中的第三个模式要求月份应该是两个数字。

  /articles/2003/ 将匹配列表中的第一个模式不是第二个,因为模式按顺序匹配,第一个会首先测试是否匹配。请像这样自由插入一些特殊的情况来探测匹配的次序。

  /articles/2003 不匹配任何一个模式,因为每个模式要求URL 以一个斜线结尾。

  /articles/2003/03/03/ 将匹配最后一个模式。Django 将调用函数views.article_detail(request, ’2003′, ’03′, ’03′)。

  

  根据url后边的数值,赋予相应的参数:id

  urls.py

  from django.conf.urls import include, url from django.contrib import admin from django_app.views import index urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^index/(?P<id>[0-9])/$', index), ]

  将对于的id参数代入查询获取数据列表中指定索引的值(忽略这的一点小细节错误)

  views.py

  from django.shortcuts import render from django_app.models import DjangoTest # Create your views here. def index(request,id): text = DjangoTest.objects.all() iden = int(id) context = {'text':text[iden]} return render(request,'index.html',context)

  模版层

  模版层语法参考

  

  
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Django test</title> </head> <body> <h1>ID: {{ text.id }}</h1> <h1>Hello:{{ text.text }} </body> </html>

  实际运行效果

  

  

  二、Django开发中的Web攻防(部分)

  

   二、Django开发中的Web攻防(部分)
1、格式化字符串漏洞

  修复前

  from django.shortcuts import render from django.contrib.auth import authenticate, login import django django.setup() # Create your views here. def index(request): if request.method == 'GET': return render(request,'index.html') else: username = request.POST['username'] password = request.POST['password'] user = authenticate(username=username,password=password) if user is not None: if user.is_active: login(request, user) template = 'Hello {user}! , You can set your email is:' + request.POST.get('email') return render(request, 'index.html', {"value": template.format(user=request.user)}) else: info = "The password is valid, but the account has been disabled!" return render(request, 'index.html', {"value": info}) else: info = "The username and password were incorrect." return render(request, 'index.html', {"value": info})

  
在原来的代码上变动了一下,如果不增加认证选项,返回的用户永远是匿名用户。

  
在原来的代码上变动了一下,如果不增加认证选项,返回的用户永远是匿名用户。

  在前边我已经创建了一个超级用户(admin admin),所以直接用这个用户来进行认证。

  认证之后返回登录用户的用户名,我们可以自己通过post方法传入一个邮箱地址上去作为临时地址,如果用户名信息出现任何错误,返回相应的错误信息。

  使用django认证系统

  

  User对象是认证系统的核心,默认user的基本属性有username、password、email…..

  

  代码中邮箱信息直接通过format拼接在了字符串中,然后展示在页面里,我们可以通过以下payload来获取敏感数据,将user变量中的password属性 作为变量信息进行拼接,从而进行获取

  payload: {user.password}

  
修复后

  
修复后

  index.html

  将其他的文本信息直接存放在模版中

  <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Django test</title> </head> <body> <h1>Hello, Django!</h1> <h2>hello {{ user }}, You can set your email is:{{ value }}</h2> </body> </html> views.py ..... email = request.POST.get('email') return render(request, 'index.html', {"value": email}) ... 2、XSS

  测试与修复前

  只是简单的接收post参数值,然后让其显示在页面上

  views.py def index(request): if request.method == 'GET': return render(request,'index.html') else: info = request.POST.get('info') return render(request,'index.html',{"value":info}) index.html <h1>Hello, Django!</h1> <h2>{{ value }}</h2>

  
当键入payload时,并没有预想的弹窗,因为django自动为开发者提供了escape功能,让html代码在render之前先进行转义,然后再显示出来。

  
当键入payload时,并没有预想的弹窗,因为django自动为开发者提供了escape功能,让html代码在render之前先进行转义,然后再显示出来。

  除了自动开启的escape,还有safe、autoescape、make_Safe等

  autoescape测试

   {% autoescape off %} <h2>{{ value }}</h2> {% endautoescape %}

  当其值为off时,即存在xss漏洞

  
safe测试

  
safe测试 <h1>Hello, Django!</h1> <h2>{{ value | safe }}</h2>

  通过safe关闭了模版的安全机制,出现XSS漏洞

  
还有几种情况也可能存在XSS:

  
还有几种情况也可能存在XSS:


  1、var mystr = “\{ \{ value | escapejs \} \}”

  2、safe、make_safe、autoescape

  3、DOM型XSS

  4、HttpResponse返回动态内容

  

  修复后

  import cgi # Create your views here. def index(request): if request.method == 'GET': return render(request,'index.html') else: info = request.POST.get('info') info = cgi.escape(info) return render(request,'index.html',{"value":info})

  
使用cgi模块需要注意:

  
使用cgi模块需要注意:

  
设为True,让其转义尽可能多的导致逃逸的字符。

  
设为True,让其转义尽可能多的导致逃逸的字符。 3、SQL注入

  Django QuerySet

  查看django queryset执行的SQL

  from django_app.models import DjangoTest as dj print dj.objects.all().query 得到 SELECT `django_app_djangotest`.`id`, `django_app_djangotest`.`text` FROM `django_app_djangotest` 简化之后就是 SELECT id,text FROM django_app_djangotest;

  
extra实现别名、条件、排序等

  
extra实现别名、条件、排序等

  以select为例:

  tag = dj.objects.all().extra(select={“tag_id”:’id’})

  
以where为例:

  
以where为例:

  extra里的允许当前的where参数可以使用原声的sql语句进行查询。

  条件为id=1,结果即查询出了一条数据

  
raw方法实现原生的SQL语句查询

  
raw方法实现原生的SQL语句查询

  a = dj.objects.raw(‘SELECT id,text FROM django_app_djangotest ‘)

  raw()方法支持索引访问(a[0])

  也可以打印当前赋予的这个变量a都有哪些方法

  

  

  直接利用API来查询数据

  

  

  直接利用API来查询数据

  django.connection

  
MySQL API

  
MySQL API

  诸如mysqldb、pymysql、mysqlclient,在views层写好sql语句,根据传入的参数值来查询,得出结果后返回给模版就可以了

  修复前

  views.py

  from django.shortcuts import render from django_app.models import DjangoTest as dj # Create your views here. def index(request): if request.method == 'GET': return render(request,'index.html') else: id = request.POST.get('id') tag = dj.objects.extra(where={'id={}'.format(id)})[0].text return render(request,'index.html',{"value":tag})

  接下来就可以进行愉快的测试了

  

  

  测试篇

  a = dj.objects.extra(where={‘id=1′})

  SELECT `django_app_djangotest`.`id`, `django_app_djangotest`.`text` FROM `django_app_djangotest` WHERE (id=1asdasdad)

  先输入payload查看django传递回数据库的sql语句是什么

  
更改后的payload

  
更改后的payload

  

  

  后边又构造测试了几个,SQL语句是正确,但是django传入SQL语句时会提示里边的语法问题,并且就算语法正确,也返回不了数据。(这其实有点问题,后边做完一想,没拿到mysql shell里边去测,终端里边测对了,再拿过来,这里有点懒没再弄)

  

  

  后边又构造测试了几个,SQL语句是正确,但是django传入SQL语句时会提示里边的语法问题,并且就算语法正确,也返回不了数据。(这其实有点问题,后边做完一想,没拿到mysql shell里边去测,终端里边测对了,再拿过来,这里有点懒没再弄)

  又因为id的值,从而在页面中显示不出来,所以这时候想到了延时注入

  
在这里调用a的时候会延时3秒

  
在这里调用a的时候会延时3秒

  
我们在Web页面中进行测试

  
我们在Web页面中进行测试

  

  

  

  

  

  关于这里的秒数是成倍关系,以前看到过一篇帖子,说是当时间满足出现成倍的关系时,应该是查询出了多条数据,每一个row执行一次延时。

  

  接下来就好办了

  x = dj.objects.extra(where={“id=1 and if(substr((select user()),1,1)=’r',sleep(3),1)”})

  
后边的步骤跟着盲注的流程走就OJBK了。

  
后边的步骤跟着盲注的流程走就OJBK了。

  有时候不要直接在django shell中执行,先去mysql命令行把命令敲对了,也确实可以执行payload时候再回来测试,确保第一步先正确。

  
刚才说了的只是extra中的where子句,其他类型的数据提取方法在前边也有说过了,具体案例具体分析

  
刚才说了的只是extra中的where子句,其他类型的数据提取方法在前边也有说过了,具体案例具体分析

  修复后

  views.py

  from django.shortcuts import render from django_app.models import DjangoTest as dj # Create your views here. def index(request): if request.method == 'GET': return render(request,'index.html') else: id = request.POST.get('id') tag = dj.objects.extra(where=['id=%s'],params=id) info = tag[0].text return render(request,'index.html',{"value":info})

  用户发送的请求再匹配到视图函数进行处理时,视图函数的相关机制会对敏感信息进行处理,导致一些恶意语句被过滤

  现在测试就不会了

  
4、待更新 4、待更新

  这两天要考试了,得花几个小时复习一下了。完了还有一部分事情得处理完毕,接着就去实习了。django攻防方面的知识自己也会去好好研究,更多的漏洞方面的知识扩展完了会补充在自己的博客上(www.addon.pub 嘿嘿嘿)。

  同时在自己探索的同时也能和方向相同的小伙伴共同探讨学习,期间也会把自己学到的以及在其中遇到的问题分享出来,让想学习的同学可以更快速的入门。

  虽然文章简单,但是还是希望可以对想要入门的同学提供一些帮助,共同成长。

  最后就祝大家学业有成,工作顺利~

  *本文作者:Yokeen,转载请注明来自FreeBuf.COM

特别声明:本文为网易自媒体平台“网易号”作者上传并发布,仅代表该作者观点。网易仅提供信息发布平台。

跟贴 跟贴 2 参与 102
© 1997-2019 网易公司版权所有 About NetEase | 公司简介 | 联系方法 | 招聘信息 | 客户服务 | 隐私政策 | 广告服务 | 网站地图 | 意见反馈 | 不良信息举报

FreeBuf

互联网安全新媒体

头像

FreeBuf

互联网安全新媒体

5491

篇文章

14179

人关注

列表加载中...
请登录后再关注
x

用户登录

网易通行证/邮箱用户可以直接登录:
忘记密码